var _startTimer = new Date().getTime();
var _lastTimer = _startTimer;
console.log("loading VLOOK ...");

const _version = "v9.3", // 版本信息
      _animateSpeed = 200, // 动画速度，值越小越快
      _icoFold =
          '<svg width="16px" height="16px"><use xlink:href="#icoFolded" class="mdx-svg-ico-dark"/></svg>', // 大纲章节图标：已收起
      _icoUnfold =
          '<svg width="16px" height="16px"><use xlink:href="#icoUnfold" class="mdx-svg-ico-dark"/></svg>', // 大纲章节图标：已展开
      _smallScreenWidth = 1000, // 大小屏分界的尺寸标准
      _reboundOffset = 10, // 动画回弹效果偏移量
      _defaultImage =
          ""; // 默认图片的元数据（BASE64编码）
  let _enableBlockFocus = false, // 是否已激活内容块聚焦模式
      _spotlightX, _spotlightY, // 用于聚光灯功能，记录鼠标当前位置
      _spotlightR = 180, // 聚光灯半径
      _currentFontStyle = null, // 记录当前字体样式，sans：非衬线，serif：衬线
      _headers = [], // 标题数据，用于构建大纲
      _foldItem = [], // 收起/展开大纲节点数据，用于构建大纲
      _lastCurrentHeaderIndex = -2, // 当前标题索引号，用于在大纲页面中自动跟踪当前标题
      _lastOutlineItem = null, // 大纲内最后一次高亮章节项
      _lastHeaderLevel = 0, // 最后标题层级，用于构建大纲
      _lastHeaderFolder = null, // 最后标题收起/展开节点，用于构建大纲
      _lastCrossTable = null, // 最后/当前显示十字光标的表格
      _lastCrossCell = null, // 最后/当前显示十字光标的表格单元格
      _outlineShowed = false, // 大纲页面是否显示的标记
      _figureCount = 0, // 插图总数
      _lastHoverContent = false, // 最后显示新标签打开按钮的内容（插图/表格等）
      _lastBlockFocusItem = null, // 最后的聚焦内容块
      _blockFocusItemIndex = -1, // 当前聚焦内容块索引
      _blockFocusItemCount = 0, // 聚焦内容块总数
      _figIndex = -1, // 插图索引
      _colorScheme = "light", // Light/Dark模式
      _colorSchemeBeforePrint = _colorScheme,
      _tipsTimer, // 用于自动控制提示显示时长
      _lang = 0; // 当前语言（浏览器中的语言配置）

  /**
   * 获得设备的DPR值
   */
  function getDPR() {
      return window.devicePixelRatio;
  }
  
  /**
   * 检查页内链接坏链
   */
  function checkInnerBadLink() {
      let count = 0;
      let badLink = "";
      $("a[href^='#']").each(function () {
          var href = $(this).attr("href");
          // 有效的页内链接的前缀为以下条件
          if (href == "#") {
              count++;
              badLink += ["无效页内链接 [",
                      "無效頁內鏈接 [",
                      "Invalid Inner Link [",
                      "Lien de page non valide [",
                      "Недопустимая ссылка на страницу [",
                      "ページリンクが無効です[",
                      "잘못된 페이지 링크["
                  ][_lang] +
                  count + "]：" + $(this).text() + " ----- " + $(this).parent().text() + "\n";
              console.error(["无效页内链接 [",
                      "無效頁內鏈接 [",
                      "Invalid Inner Link [",
                      "Lien de page non valide [",
                      "Недопустимая ссылка на страницу [",
                      "ページリンクが無効です [",
                      "잘못된 페이지 링크 ["
                  ][_lang] +
                  count + "]：" + $(this).text() + " ----- " + $(this).parent().text());
          }
      });
      // 显示无效链接信息
      if (badLink.length > 0)
          alert(badLink);
  }

  /**
   * 检查重名的Header
   */
  function checkDuplicateHeader() {
      let h = [];
      $(":header").each(function (i, n) {
          h.push($(n).text());
      });
      let dupHeaders = [];
      const ignoreHeaders = "业务规则,通用的业务规则,用户界面与交互,通用的用户界面与交互,页面流程,业务主流程,流程图,状态图,数据接入";
      for (let i in h) {
          for (let k in h) {
              if (i != k && h[i] == h[k] &&
                  ignoreHeaders.indexOf(h[k]) < 0)
                  dupHeaders.push(h[i]);
          }
      }
      // 输出警告信息
      for (let i in dupHeaders)
          console.warn(["重名的标题 [",
                  "重複的標題 [",
                  "Duplicate Header [",
                  "Titre en double [",
                  "Дублирующее название [",
                  "重複するタイトル [",
                  "중복 제목 ["
              ][_lang] +
              i + "]：" + dupHeaders[i]);
  }

  /**
   * 检查是否为空对象
   */
  function isEmptyObject(obj) {
      return (typeof (obj) == "undefined");
  }

  /**
   * 以指定字符开始
   */
  String.prototype.startWith = function (s) {
      if (s == null || s == "" || this.length == 0 || s.length > this.length)
          return false;
      return this.substr(0, s.length) == s;
  }
  /**
   * 以指定字符结束
   */
  String.prototype.endWith = function (s) {
      if (s == null || s == "" || this.length == 0 || s.length > this.length)
          return false;
      return this.substring(this.length - s.length) == s;
  }

  /**
   * 隐藏大纲（异常情况使用）
   */
  function hideOutlineOnError() {
      $(".mdx-toc-box").hide();

      console.error(["文档中没有找到目录信息，请用Typora最新版本导出，并应用最新VLOOK插件",
          "文檔中沒有找到目錄信息，請用Typora最新版本導出，並應用最新VLOOK插件",
          "No [TOC] information was found in the document, export it with the latest version of Typora and apply the latest VLOOK plug-in.",
          "Les informations du répertoire ne figurent pas dans la documentation, veuillez les exporter avec la dernière version de Typora et appliquer le dernier plug-in VLOOK.",
          "Информация в каталоге не найдена в документации, пожалуйста, экспортируйте ее с последней версией Typora и примените последний плагин VLOOK",
          "ドキュメントにディレクトリ情報が見つからない場合は、Typoraの最新バージョンでエクスポートし、最新のVLOOKプラグインを適用してください",
          "설명서에 디렉토리 정보가 없으므로 Typora 최신 버전으로 내보내고 최신 VLOOK 플러그인을 적용하십시오."
      ][_lang]);
  }

  /**
   * 为Outline中子元素添加附加属性和事件
   */
  function initOutlineData() {
      // 提取文档中由[toc]标签生成的文档目录作为浮动outline中的内容
      let t = $(".md-toc");
      // 没有生成目录
      if (isEmptyObject(t)) {
          hideOutlineOnError();
          return false;
      }

      // 有生成目录
      let toc = $(".mdx-toc-box-body");
      // 复制toc内容
      toc.append(t.clone()); // 复制toc模式
      t.hide();

      let tocContent = $(".md-toc-content");
      // 没有目录内容
      if (isEmptyObject(tocContent)) {
          hideOutlineOnError();
          return false;
      }
      // 有目录内容
      tocContent.children().each(function () {
          let item = $(this);
          // 只处理h1-h5，忽略h6
          if (item.attr("class").indexOf("-h6") == -1) {
              // 将目录记录到标题数组中
              let href = item.children().attr("href");
              _headers.push(href.indexOf("#") > -1 ? href.substr(1, href.length) : href);
              item.css("cursor", "pointer"); // 添加鼠标形状
              // 自定义大纲节点元数据
              item.attr({
                  "id": "oli-header-" + item.attr("data-ref"), // 添加id属性
                  "data-node": "0", // 添加节点类型：0:叶子节点, 1:目录节点
                  "data-folding": "1", // 添加节点状态：0:收起, 1:展开
                  "title": item.find("a").text().trim()
              });
              // 所有大纲节点都添加folding空白控件备用
              $("<div id='fd-oli-header-" + item.attr("data-ref") + "' class='mdx-folder'>&nbsp;</div>")
                  .insertBefore(item.find("a"));
              // 点击大纲节点事件
              item.click(function () {
                  hideOutline();
                  location.href = "#header-" + item.attr("data-ref");
              });

              // 记录所有非叶子节点的folder控件
              if (_lastHeaderFolder != null) {
                  // 当前节点比上一个节点层级低，则上一节点为可折叠的节点
                  if (getCSSHeaderLevel(item) > _lastHeaderLevel) {
                      _foldItem.push(_lastHeaderFolder);
                  }
              }
              // 更新最后处理的folder控件
              _lastHeaderFolder = $("#fd-oli-header-" + item.attr("data-ref"));
              _lastHeaderLevel = getCSSHeaderLevel(item);
          }
      });
      return true;
  }

  /**
   * 初始化内容块聚焦模式
   */
  function initBlockFocus() {
      // 先清理多余的段落标签
      $("li > p:only-child").contents().unwrap();

      $("h1, h2, h3, h4, h5, h6, ul > li, ol > li, p[class!=md-toc-content], .md-fences, figure, .md-diagram-panel, .MathJax_SVG_Display").each(function () {
          let item = $(this);
          // 跳过子元素有嵌套p的情况，如li > p
          if (item.children("p").length == 0) {
              item.attr("id", "mdx-blockfocus-" + _blockFocusItemCount);
              item.attr("mdx-blockfocus-index", _blockFocusItemCount);
              // 双击内容块激活内容块聚焦模式
              item.dblclick(function () {
                  _enableBlockFocus = !_enableBlockFocus;
                  if (_enableBlockFocus == true)
                      item.click();
              });
              // 单击内容块处理
              item.click(function () {
                  if (_enableBlockFocus == false)
                      return;

                  if (isFallInCrossTable($(this)) == false)
                      hideTableCross();

                  _blockFocusItemIndex = $(this).attr("mdx-blockfocus-index");

                  // 若已显示则隐藏
                  if (_lastBlockFocusItem != null && _lastBlockFocusItem.attr(
                          "mdx-blockfocus-index") == _blockFocusItemIndex)
                      hideBlockFocus();
                  else if (isFallInCrossTable($(this)) == false) {
                      gotoBlockFocusItem($(this), false);
                      event.stopPropagation(); // 停止事件冒泡
                  }
              });
              _blockFocusItemCount++;
          }
      });

      $(".md-toc-content").each(function () {
          let item = $(this);
          item.removeAttr("id");
          item.removeAttr("mdx-blockfocus-index");
          item.unbind("click");
      });
  }

  /**
   * 判断当前内容块是否与已显示了十字光标的表格重叠
   */
  function isFallInCrossTable(obj) {
      return (_lastCrossTable != null && obj.children().attr("id") == _lastCrossTable.attr("id"));
  }

  /**
   * 跳到指定的内容块，或最新的_blockFocusItemIndex指定的内容块
   */
  function gotoBlockFocusItem(it, jump) {
      hideBlockFocus();

      let item = $("#mdx-blockfocus-" + _blockFocusItemIndex);
      if (it != null)
          item = it;
      item.addClass("mdx-current-blockfocus-item");
      _lastBlockFocusItem = item;

      // 显示工具栏新手提示：内容块聚焦
      if (window.localStorage && localStorage["VLOOK-" + _version + "-hint-for-green-hand-step-bf"] == undefined) {
          showInfoTips([
                  "<strong>已激活内容聚焦模式</strong><br>鼠标直接点击内容，或键盘操作：<div style='text-align:left'><kbd>J</kbd> - 下一个<br><kbd>K</kbd> - 上一个<br><kbd>H</kbd> - 往回跳十个<br><kbd>L</kbd> - 往后跳十个<br><kbd>ESC</kbd> - 隐藏聚焦</div>",
                  "<strong>激活的內容聚焦模式</strong><br>鼠標點擊內容或鍵盤操作：<div style='text-align:left'><kbd>J</kbd>下一個<br><kbd>K</kbd>上一個<br><kbd>H</kbd>往前跳十個<br><kbd>L</kbd>往後跳十個<br><kbd>ESC</kbd> - 隱藏聚焦</div>",
                  "<strong>Activated Content Focus Mode</strong><br>Mouse click on the content, or keyboard operation:<div style='text-align:left'><kbd>J</kbd> - Next<br><kbd>K</kbd> - Previous<br><kbd>H</kbd> - Jump up ten<br><kbd>L</kbd> - Jump ten<br><kbd>ESC</kbd> - Hide focus</div>",
                  "<strong>Mode de focus du contenu activé</strong><br>Cliquez sur le contenu ou sur le clavier:<div style='text-align:left'><kbd>J</kbd> - Suivant<br><kbd>K</kbd> - Précédent<br><kbd>H</kbd> - Saut dix en avant<br><kbd>L</kbd> - Saut dix en arrière<br><kbd>ESC</kbd> - Masquer le focus</div>",
                  "<strong>Активированный режим фокусировки содержимого</strong><br>Щелчок мышью по содержимому или операции с клавиатурой:<div style='text-align:left'><kbd>J</kbd> - Далее<br><kbd>K</kbd> - Предыдущий<br><kbd>H</kbd> - Прыгай десять вперед<br><kbd>L</kbd> - прыгай десять назад<br><kbd>ESC</kbd> - Скрыть фокус</div>",
                  "<strong>アクティブコンテンツフォーカスモード</strong><br>コンテンツをマウスでクリックするかキーボード操作をします。<div style='text-align:left'><kbd>J</kbd> - 次へ<br><kbd>K</kbd> - 前へ<br><kbd>H</kbd> - 10ジャンプします<br><kbd>L</kbd> - 10ジャンプ<br><kbd>ESC</kbd> - フォーカスを隠す</div>",
                  "<strong>활성 컨텐츠 포커스 모드</strong><br>내용을 마우스로 클릭하거나 키보드 조작:<div style='text-align:left'><kbd>J</kbd> - 다음<br><kbd>K</kbd> - 이전<br><kbd>H</kbd> - 앞으로 10 칸 이동하십시오<br><kbd>L</kbd> - 점프 10 뒤로<br><kbd>ESC</kbd> - 포커스 숨기기</div>"
              ][_lang],
              10000, false);
          localStorage["VLOOK-" + _version + "-hint-for-green-hand-step-bf"] = true;
      }

      if (jump == true &&
          item.offset().top != 0 &&
          ((item.offset().top - 50) < $(document).scrollTop() ||
              (item.offset().top + 50) > ($(document).scrollTop() + $(window).height()))) {
          $('html,body').animate({
              scrollTop: item.offset().top - $(window).height() / 2
          }, _animateSpeed);
      }
  }

  /**
   * 上一个内容块item
   */
  function prevBlockFocusItem(step) {
      hideTableCross();
      if (_blockFocusItemIndex > 0) {
          _blockFocusItemIndex = parseInt(_blockFocusItemIndex) - step;
          if (_blockFocusItemIndex < 0)
              _blockFocusItemIndex = 0;
          gotoBlockFocusItem(null, true);
      }
  }

  /**
   * 下一个内容块item
   */
  function nextBlockFocusItem(step) {
      hideTableCross();
      if (_blockFocusItemIndex < _blockFocusItemCount - 1) {
          _blockFocusItemIndex = parseInt(_blockFocusItemIndex) + step;
          if (_blockFocusItemIndex > _blockFocusItemCount - 1)
              _blockFocusItemIndex = _blockFocusItemCount - 1;
          gotoBlockFocusItem(null, true);
      }
  }

  /**
   * 初始化表格数据
   */
  function initTable() {
      let colSpanCount = 0;
      let colSpanCell, lastCell = null;
      let tblData = [],
          tblSpan = [],
          tblTd2ThData = [];
      let rowIndex = 0,
          colIndex = 0;
      let needRowSpan = false;
      let tableIndex = 0;

      $("table").each(function () {
          // 新标签打开的按钮
          let table = $(this);
          // 表格索引号
          table.attr("id", "mdx-tbl" + tableIndex);
          table.hover(function () {
              // 鼠标移入显示
              showFigureAction(table);
          }, function () {
              // 鼠标移出隐藏
              hideFigureAction(table);
          });

          // 单元格处理
          table.find("tr").each(function () {
              tblData[rowIndex] = [];
              tblSpan[rowIndex] = [];
              $(this).find("td, th").each(function () {
                  let cell = $(this);

                  // --- 当前单元格十字高亮 ---
                  // 单元格行列索引号
                  cell.attr("mdx-col", "mdx-tbl" + tableIndex + "-" + colIndex);

                  // 鼠标点击单元格时显示十字光标
                  cell.click(function () {
                      hideTableCross();
                      hideBlockFocus();

                      _lastCrossCell = cell;
                      _lastCrossTable = table;

                      let tdH = parseInt(_lastCrossCell.css("height")),
                          tdW = parseInt(_lastCrossCell.css("width")),
                          tbW = parseInt(_lastCrossTable.css("width"));

                      // 横向左边
                      $(".mdx-table-cross-left").css({
                          "display": "block",
                          "top": _lastCrossCell.offset().top,
                          "left": _lastCrossTable.offset().left,
                          "height": tdH,
                          "width": _lastCrossCell.offset().left -
                              _lastCrossTable.offset().left,
                          "z-index": 9
                      });

                      // 横向右边
                      // $(".mdx-table-cross-right").css({"width": 0});
                      $(".mdx-table-cross-right").css({
                          "display": "block",
                          "top": _lastCrossCell.offset().top,
                          "left": _lastCrossCell.offset().left + tdW,
                          "height": tdH,
                          "width": _lastCrossTable.offset().left + tbW -
                              _lastCrossCell.offset().left - tdW,
                          "z-index": 9
                      });

                      // 竖向上边
                      $(".mdx-table-cross-up").css({
                          "display": "block",
                          "top": _lastCrossTable.offset().top,
                          "left": _lastCrossCell.offset().left,
                          "height": _lastCrossCell.offset().top -
                              _lastCrossTable.offset().top,
                          "width": tdW,
                          "z-index": 9
                      });

                      // 竖向下边
                      // $(".mdx-table-cross-down").css({"height": 0});
                      $(".mdx-table-cross-down").css({
                          "display": "block",
                          "top": _lastCrossCell.offset().top + tdH,
                          "left": _lastCrossCell.offset().left,
                          "height": _lastCrossTable.offset().top + parseInt(
                                  _lastCrossTable.css("height")) -
                              _lastCrossCell.offset().top - tdH,
                          "width": tdW,
                          "z-index": 9
                      });
                  });

                  // --- 行合并预处理 ---
                  // 克隆表格数据
                  tblData[rowIndex][colIndex] = cell;
                  tblSpan[rowIndex][colIndex] = 0;
                  // 行合并标记
                  if (cell.text() == "..") {
                      tblSpan[rowIndex][colIndex] = 1;
                      needRowSpan = true;
                  }
                  colIndex++;

                  // --- 列合并 ---
                  // 列合并标记
                  if (cell.text() == "==") {
                      colSpanCount++;
                      cell.remove();
                      if (colSpanCount == 1)
                          colSpanCell = lastCell;
                  } else { // 列合并
                      if (colSpanCount > 0) {
                          colSpanCell.attr("colspan", colSpanCount + 1);
                          colSpanCell.css("text-align", "center");
                      }
                      colSpanCount = 0;
                  }
                  lastCell = cell;
              }); // find(td, th)

              // 列合并（对于最后一列的补充处理）
              if (colSpanCount > 0) {
                  colSpanCell.attr("colspan", colSpanCount + 1);
                  colSpanCell.css("text-align", "center");
              }
              colSpanCount = 0;

              table.attr("mdx-cols", colIndex); // 表格列数
              rowIndex++;
              colIndex = 0;
          }); // tr

          // --- 统一整列格式 ---
          $(this).find("tr th").each(function () {
              if ($(this).find("strong").length > 0)
                  $("[mdx-col=" + $(this).attr("mdx-col") + "]").addClass("mdx-table-td-bold");
              else if ($(this).find("em").length > 0)
                  $("[mdx-col=" + $(this).attr("mdx-col") + "]").css("font-style", "italic");
              else if ($(this).find("u").length > 0)
                  $("[mdx-col=" + $(this).attr("mdx-col") + "]").css("text-decoration", "underline");
              else if ($(this).find("mark").length > 0)
                  $("[mdx-col=" + $(this).attr("mdx-col") + "]").contents().wrap("<mark></mark>");
              else if ($(this).find("del").length > 0)
                  $("[mdx-col=" + $(this).attr("mdx-col") + "]").contents().wrap("<del></del>");
          });

          rowIndex = 0;

          // 行合并
          if (needRowSpan == true) {
              tblTd2ThData = [];
              // 列式遍历（从左到右）
              for (let c = 0; c < tblSpan[0].length; c++) {
                  let rowSpanCount = 0,
                      rowSpanCell = null;
                  let r = 0,
                      thSpanFlag = false;

                  // 列式遍历（从上到下）
                  while (r < tblSpan.length) {
                      if (tblSpan[r][c] == 1) { // 要合并
                          rowSpanCount++;
                          // tblData[r][c].remove(); // 移除要被合并的单元格
                          if (rowSpanCell == null) {
                              rowSpanCell = tblData[r - 1][c];
                          }
                          // 记录最大列头行合并深度
                          if (r == 1)
                              thSpanFlag = true;
                          if (thSpanFlag == true)
                              tblTd2ThData[tblTd2ThData.length] = tblData[r][c].parent();
                          tblData[r][c].remove(); // 移除要被合并的单元格
                      } else {
                          thSpanFlag = false;
                          // 单元格行合并
                          if (rowSpanCell != null) {
                              rowSpanCell.attr("rowspan", rowSpanCount + 1);
                              rowSpanCount = 0;
                              rowSpanCell = null;
                          }
                      }
                      r++;
                  } // while
                  // 单元格行合并（对于最后一行的补充处理）
                  if (rowSpanCell != null) {
                      rowSpanCell.attr("rowspan", rowSpanCount + 1);
                      rowSpanCell.css("text-align", "center");
                  }
              } // for

              for (let i = 0; i < tblTd2ThData.length; i++) {
                  tblData[0][0].parent().parent().append(tblTd2ThData[i]);
              }
          } // if

          let figCaption = ["表.",
              "表.",
              "Table.",
              "Table.",
              "Таблица.",
              "テーブル.",
              "표."
          ][_lang] + (tableIndex + 1);
          // 有指定的图注文本
          let fc = getFigureCaption(table.parent().prev());
          if (fc != null && fc.trim().length > 0)
              figCaption = figCaption + " - " + fc;
          // 为插图增加图注
          table.wrap("<div id='tbl-num" + tableIndex + "' class='mdx-figure-alt'></div>");
          table.before("<span>" + figCaption + "</span>");

          tableIndex++;
          needRowSpan = false;
      }); // table
  }

  /**
   * 隐藏表格十字聚焦
   */
  function hideTableCross() {
      if (_lastCrossCell == null)
          return;

      $(".mdx-table-cross").hide();
      _lastCrossCell = null;
      _lastCrossTable = null;
  }

  /**
   * 初始化插图数据
   */
  function initFigureData() {
      let ignoreImgLost = false;
      $("img, .md-diagram-panel svg").each(function () {
          let fig = $(this);
          // 添加插图标识数据
          fig.attr({
              "fig-id": "mdx-figure-" + _figureCount,
              "fig-idx": _figureCount,
              "fig-type": fig.prop("tagName").toLowerCase()
          });
          // 添加插图样式
          fig.css("cursor", "pointer");
          fig.addClass("mdx-figure");

          // 添加锚点，便于在插图浏览器直接跳转至对应插图位置
          $("<a name='" + "fig-idx" + _figureCount + "'>").insertBefore(fig.parent());

          // 添加鼠标单击事件
          fig.click(function () {
              showFigureViewer(fig);
          });
          // 添加鼠标移入/移出事件
          fig.mouseenter(function () {
              showFigureAction(fig);
          });
          fig.mouseout(function () {
              hideFigureAction(fig);
          });

          let fc = null;
          // 图片插图的处理
          if (fig.attr("fig-type").toLowerCase() == "img") {
              fc = fig.attr("alt"); // 获取插图标题
              let src = fig.attr("src");
              // 图片无法加载时加载默认图片
              fig.bind("error", function () {
                  if (fig.attr("src").indexOf("vlook-lost-image.jpg") == -1)
                      if (ignoreImgLost == false)
                          ignoreImgLost = !confirm(["图片缺失：",
                              "圖片缺失：",
                              "Lost Image: ",
                              "Image perdue: ",
                              "Потерянное изображение: ",
                              "失われた画像：",
                              "잃어버린 이미지 : "
                          ][_lang] + fig.parent().text() + "\"" + fig.attr("src") + "\"" + [
                              "\n\n继续检查吗？",
                              "\n\n繼續檢查嗎？",
                              "\n\nContinue to check?",
                              "\n\nContinuer à vérifier?",
                              "\n\nПродолжить проверку?",
                              "\n\nチェックを続けますか？",
                              "\n\n계속 확인 하시겠습니까?"
                          ][_lang]);

                  loadDefaultImage($(this));
              });

              // 强制重新加载一次以触发error事件
              fig.attr("src", src);

              // 处理在 Dark Mode 指定反转的图片
              if (getQueryString(src.substring(src.indexOf("?"), src.length))["invert"] == "in-dark") {
                  // console.log(src + "invert in dark");
                  fig.attr("vlook-invert", "in-dark");
              }
          }
          // SVG插图的处理
          else if (fig.attr("fig-type").toLowerCase() == "svg") {
              // 获取插图标题
              fc = getFigureCaption(fig.parent().prev().prev());
          }

          let figCaption = ["图.",
              "圖.",
              "Figure.",
              "La figure.",
              "карта.",
              "図.",
              "그림."
          ][_lang] + (_figureCount + 1);

          // 有指定的图注文本
          if (fc != null && fc.trim().length > 0)
              figCaption = figCaption + " - " + fc;

          // 为插图增加图注
          fig.wrap("<div id='fig-num" + _figureCount + "' class='mdx-figure-alt'></div>");
          fig.before("<span>" + figCaption + "</span>");

          // 修正在SVG插图套上图注figure-alt后的自适应尺寸
          if (fig.attr("fig-type").toLowerCase() == "svg")
              fig.parent().css("width", "100%");

          _figureCount++;
      });
      if (_figureCount > 0)
          $(".mdx-btn-figure-launcher").css("visibility", "visible");
  }

  /**
   * 返回插图、表格上方H6的内容为图注或表注
   */
  function getFigureCaption(caption) {
      if (caption != null
          && caption.prop("tagName") != undefined
          && caption.prop("tagName").toLowerCase() == "h6")
          return caption.text();
      return null;
  }

  /**
   * 加载默认图片
   */
  function loadDefaultImage(fig) {
      fig.attr({
          "src-org": fig.attr("src"),
          "src": _defaultImage
      });
  }

  /**
   * 显示插图浏览器
   */
  function showFigureViewer(fig) {
      if (_figureCount == 0)
          return;
      if (_figIndex == -1)
          _figIndex = 0;
      if (fig == null)
          fig = $("[fig-id='mdx-figure-" + _figIndex + "']");

      let viewer = $(".mdx-figure-viewer");
      viewer.css({
          "top": viewer.css("height"),
          "opacity": 0
      });

      // 调整插图动作按钮层级
      let act = $(".mdx-figure-action");
      act.css("z-index", parseInt(act.css("z-index")) + parseInt(viewer.css("z-index")));

      hideFigureAction(null);

      // 在插图浏览器中显示对应插图
      _figIndex = fig.attr("fig-idx");

      viewer.show();
      viewer.animate({
              top: 0, // - _reboundOffset,
              opacity: 1
          },
          _animateSpeed,
          function () {
              showFigureContent();
              updateFigureViewerUI();
          });
  }

  /**
   * 关闭插图浏览器
   */
  function hideFigureViewer() {
      let viewer = $(".mdx-figure-viewer");
      viewer.animate({
          top: viewer.css("height"),
          opacity: 0
      }, _animateSpeed, function () {
          $(".mdx-figure-content").empty();
          viewer.hide();
      });

      // 调整插图动作按钮层级
      let act = $(".mdx-figure-action"),
          actIdx = parseInt(act.css("z-index")),
          viewerIdx = parseInt(viewer.css("z-index"))
      if (actIdx > viewerIdx)
          act.css("z-index", actIdx - viewerIdx);

      hideFigureAction(null);
      hideMask();
  }

  /**
   * 鼠标移出插件动作按钮
   */
  function outFigureAction() {
      if (mouseDropInObj(_lastHoverContent) == false)
          $(".mdx-figure-action").hide();
  }

  /**
   * 显示插图动作按钮
   */
  function showFigureAction(fig) {
      if (env.device.mobile)
          return;

      const radius = fig.css("border-top-left-radius");
      let act = $(".mdx-figure-action");
      act.hide();
      act.css({
          "left": fig.offset().left,
          "top": fig.offset().top,
          "border-top-left-radius": radius
      });

      act.fadeIn(_animateSpeed);
      _lastHoverContent = fig;
  }

  /**
   * 隐藏插图动作按钮
   */
  function hideFigureAction(fig) {
      if (fig == null || mouseDropInObj(fig) == false)
          $(".mdx-figure-action").fadeOut(_animateSpeed);
  }

  /**
   * 在新标签页中打开插图/表格等内容
   */
  function openContentInNewTab() {
      if (_lastHoverContent == null)
          return;

      const bgColor = $("body").css("background-color"),
          fgColor = $("body").css("color");

      // ondblclick, onmousemove, onkeydown中的代码须使用原生javascipt
      let newTab = window.open("", "_blank"),
          baseContent = "<body" +
          " onmousemove=\"if (document.getElementsByClassName('mdx-spotlight')[0].style.display=='block'){var e = window.event;document.documentElement.style.setProperty('--spotlightX', e.clientX);document.documentElement.style.setProperty('--spotlightY', e.clientY);}\"" +
          " onkeydown='var code = event.keyCode||event.which||event.charCode;if (code == 27) document.getElementsByClassName(\"mdx-spotlight\")[0].style.display=\"none\"; if (code != 83) return; var obj=document.getElementsByClassName(\"mdx-spotlight\")[0];if(obj.style.display==\"block\"){obj.style.display=\"none\"}else{obj.style.display=\"block\";var e=window.event;document.documentElement.style.setProperty(\"--spotlightX\",e.clientX);document.documentElement.style.setProperty(\"--spotlightY\",e.clientY);document.documentElement.style.setProperty(\"--spotlightR\",180);}'" +
          " class='typora-export' style='min-height:100vh; color:" + fgColor + "; background-color:" + bgColor +
          "'><div class='mdx-spotlight'></div>" +
          "<div id='write' class='is-mac' style='margin-left: 0;'>",
          caption = "";

      newTab.document.write("<!doctype html>");
      newTab.document.write($("html").html());

      newTab.document.title = _lastHoverContent.prev().text();

      // 图片
      if (_lastHoverContent.attr("fig-type") == "img") {
          let newObj = _lastHoverContent.clone();
          newObj.css({
              "border-radius": "15px"
          });

          newTab.document.body.outerHTML = baseContent +
              newObj.prop("outerHTML") + "</div></div></body>";
      }
      // mermaid / flow.js等SVG图
      else if (_lastHoverContent.attr("fig-type") == "svg") {
          let newObj = _lastHoverContent.clone();
          newObj.css({
              "border-radius": "15px"
          });

          newTab.document.body.outerHTML = baseContent + "<div class='md-diagram-panel'>" +
              newObj.prop("outerHTML") + "</div></div></body>";
      }
      // 表格
      else if (_lastHoverContent.prop("tagName").toLowerCase() == "table") {
          let newObj = _lastHoverContent.clone();
          newTab.document.body.outerHTML = baseContent + "<h1 style='display:none'>" + ["表格", "table", "Table", "table",
                  "table"
              ][_lang] + "</h1><figure>" +
              newObj.prop("outerHTML") + "</figure></div></div></body>";
      }

      // 初始化新标签页面
      newTab.initVLOOK(_colorScheme);
      
      newTab.adjustColorScheme();
      newTab.adjustImageInverInDarkMode();

      newTab.updateFigureAlt(newTab.document.title);
  }

  /**
   * 更新插图的图注、表注（用于在新标签打开插图、表格后的强制更新对应内容）
   */
  function updateFigureAlt(caption) {
      $(".mdx-figure-alt > span").text(caption);
  }

  /**
   * 鼠标光标落入指定对象范围内
   */
  function mouseDropInObj(obj) {
      let e = window.event;
      const mx = e.pageX || e.clientX + document.body.scrollLeft;
      const my = e.pageY || e.clientY + document.body.scrollTop;
      if (mx < obj.offset().left || mx > (obj.offset().left + obj.width()) ||
          my < obj.offset().top || my > (obj.offset().top + obj.height()))
          return false;
      return true;
  }

  /**
   * 显示插图内容
   */
  function showFigureContent() {
      let fig = $("[fig-id=mdx-figure-" + _figIndex + "]"),
          content = $(".mdx-figure-content");
      content.empty();
      content.show();
      content.css({
          "width": $(window).width(),
          "height": $(window).height()
      });

      let newObj = fig.clone();
      newObj.css({
          "max-width": $(window).width() - 90,
          "max-height": $(window).height() - 90,
          "display": "inline-block",
          "cursor": "pointer",
          "border-radius": "15px",
      });
      newObj.click(function () {
          gotoFigure();
          hideFigureViewer();
      });
      content.append(newObj);

      newObj.mouseenter(function () {
          showFigureAction(newObj);
      });
      newObj.mouseout(function () {
          hideFigureAction(newObj);
      });
  }

  /**
   * 查看上一个插图
   */
  function prevFigure() {
      if (_figIndex > 0) {
          _figIndex--;
          hideFigureAction();
          showFigureContent();
          updateFigureViewerUI();
      }
  }

  /**
   * 查看下一个插图
   */
  function nextFigure() {
      if (_figIndex < _figureCount - 1) {
          _figIndex++;
          hideFigureAction();
          showFigureContent();
          updateFigureViewerUI();
      }
  }

  /**
   * 更新插图浏览器界面
   */
  function updateFigureViewerUI() {
      let btnPrev = $(".mdx-btn-prev-figure");
      let btnNext = $(".mdx-btn-next-figure");
      let pageNum = $(".mdx-figure-pagenum");
      let viewer = $(".mdx-figure-viewer");

      // 更新插图页码
      var title = ["(共",
          "(共",
          "(Total ",
          "(Totale ",
          "(Всего ",
          "(合計",
          "(합계"
      ][_lang] + _figureCount + ["张) ",
          "張) ",
          ") ",
          ") ",
          ") ",
          "張) ",
          "장) "
      ][_lang];
      title += "<strong>" + $("#fig-num" + _figIndex + " > span").text() + "</strong>";
      pageNum.css("width", (viewer.width()) - 60);
      pageNum.html(title);

      // 更新导航按钮位置
      btnPrev.css("top", (viewer.height() - 30) / 2);
      btnNext.css({
          "top": btnPrev.css("top"),
          "right": "10px"
      });

      // 根据当前插图索引更新浏览按钮有效状态
      btnPrev.css("opacity", "0");
      btnNext.css("opacity", "0");
      if (_figIndex > 0) {
          btnPrev.css("opacity", "1");
      }
      if (_figIndex < _figureCount - 1) {
          btnNext.css("opacity", "1");
      }
  }

  /**
   * 通过插图浏览器中转到文档插图位置
   */
  function gotoFigure() {
      $(".mdx-figure-content").click(function () {
          window.location.href = "#fig-idx" + _figIndex;
          hideFigureViewer();
      });
  }

  /**
   * 初始化UI国际化内容
   */
  function initUIi18n() {
      switch (env.language.base) {
          case "zh":
              _lang = 1; // 繁体中文
              if (env.language.subset.toLowerCase() == "cn" || env.language.subset.toLowerCase() == "chs")
                  _lang = 0; // 简体中文
              break;
          case "en":
              _lang = 2; // 英
              break;
          case "fr":
              _lang = 3; // 法
              break;
          case "ru":
              _lang = 4; // 俄
              break;
          case "ja":
              _lang = 5; // 日
              break;
          case "ko":
              _lang = 6; // 韩
              break;
          default:
              _lang = 2; // 英
      }

      $(".mdx-toc-box-title").attr("title", ["查看文档封面",
          "查看文檔封面",
          "View Document Cover",
          "Voir la couverture du document",
          "Просмотреть обложку документа",
          "ドキュメントカバーを表示する",
          "문서 표지보기"
      ][_lang]);

      $(".mdx-btn-outline").attr("tips", ["<kbd>O</kbd> - 隐藏 / 显示大纲面板",
          "<kbd>O</kbd> - 隱藏 / 顯示大綱面板",
          "<kbd>O</kbd> - Hide / Show Outline Panel",
          "<kbd>O</kbd> - Cacher / Afficher le panneau de contour",
          "<kbd>O</kbd> - Скрыть / показать панель",
          "<kbd>O</kbd> - アウトラインパネルの非表示/表示",
          "<kbd>O</kbd> - 개요 패널 숨기기 / 표시"
      ][_lang]);

      $(".mdx-btn-nav-back").attr("tips", ["后退",
          "後退",
          "Go back",
          "Retourner",
          "Возвращаться",
          "戻る",
          "돌아 가기)"
      ][_lang]);

      $(".mdx-btn-nav-forward").attr("tips", ["前进",
          "前進",
          "Go forward",
          "Aller de l'avant",
          "Иди вперед",
          "前進する",
          "앞으로 이동"
      ][_lang])

      $(".mdx-btn-fullscreen").attr("tips", ["<kbd>F</kbd> - 切换全屏",
          "<kbd>F</kbd> - 切換全屏",
          "<kbd>F</kbd> - Toggle Fullscreen",
          "<kbd>F</kbd> - Changer en plein écran",
          "<kbd>F</kbd> - Переключить полный экран",
          "<kbd>F</kbd> - フルスクリーンに切り替える",
          "<kbd>F</kbd> - 전체 화면 전환"
      ][_lang]);

      $(".mdx-btn-color-scheme").attr("tips", ["<kbd>T</kbd> - 切换 [ 黑暗 / 明亮 ] 模式",
          "<kbd>T</kbd> - 切換 [ 黑暗 / 明亮 ] 模式",
          "<kbd>T</kbd> - Switch Dark/Light Mode",
          "<kbd>T</kbd> - Basculer en mode sombre / clair",
          "<kbd>T</kbd> - Переключить темный / светлый режим",
          "<kbd>T</kbd> - ダーク/ライトモードの切り替え",
          "<kbd>T</kbd> - 다크 / 라이트 모드 전환"
      ][_lang]);

      $(".mdx-btn-font-style").attr("tips", ["<kbd>A</kbd> - 切换 字体风格",
          "<kbd>A</kbd> - 切換 字體風格",
          "<kbd>A</kbd> - Switch Font Style",
          "<kbd>A</kbd> - Changer de style de police",
          "<kbd>A</kbd> - Переключить стиль шрифта",
          "<kbd>A</kbd> - フォントスタイルの切り替え",
          "<kbd>A</kbd> - 글꼴 스타일 전환"
      ][_lang]);

      $(".mdx-btn-figure-launcher").attr("tips", ["<kbd>I</kbd> - 查看文档插图",
          "查看文檔插圖",
          "<kbd>I</kbd> - View Document Figures",
          "<kbd>I</kbd> - Afficher l'illustration du document",
          "<kbd>I</kbd> - Просмотр иллюстрации документа",
          "<kbd>I</kbd> - ドキュメントの図を表示",
          "<kbd>I</kbd> - 문서 그림보기"
      ][_lang]);

      $(".mdx-btn-spotlight").attr("tips", ["<kbd>S</kbd> - 打开 / 关闭聚光灯<br><kbd>Z</kbd> - 打开聚光灯后调整大小",
          "<kbd>S</kbd> - 打開 / 關閉聚光燈<br><kbd>Z</kbd> - 打開聚光燈後調整大小",
          "<kbd>S</kbd> - Turn the spotlight ON/OFF<br><kbd>Z</kbd> - Resize after turning on the spotlight",
          "<kbd>S</kbd> - Allumer/éteindre le projecteur, <kbd>Z</kbd> - Redimensionner après avoir allumé le projecteur",
          "<kbd>S</kbd> - Включите/выключите прожектор, <kbd>Z</kbd> - Изменить размер после включения прожектора",
          "<kbd>S</kbd> - スポットライトをオン/オフにする, <kbd>Z</kbd> - スポットライトをオンにした後のサイズ変更",
          "<kbd>S</kbd>　스포트라이트 켜기 / 끄기 (S, 또는 문서를 두 번 클릭), <kbd>Z</kbd> - 스포트라이트를 켠 후 크기 조정"
      ][_lang]);

      $(".mdx-btn-print").attr("tips", ["<kbd>P</kbd> - 打印...",
          "<kbd>P</kbd> - 打印...",
          "<kbd>P</kbd> - Print...",
          "<kbd>P</kbd> - Imprimer...",
          "<kbd>P</kbd> - Печать...",
          "<kbd>P</kbd> - 印刷する...",
          "<kbd>P</kbd> - 인쇄..."
      ][_lang]);

      $(".mdx-nav-prev").attr("tips", ["<kbd>←</kbd> / <kbd>&lt;</kbd> - 前一章节",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - 前一章節",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - Previous Chapter",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - Chapitre Précédent",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - Предыдущая глава",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - 前の章",
          "<kbd>←</kbd> / <kbd>&lt;</kbd> - 이전 장"
      ][_lang]);

      $(".mdx-nav-next").attr("tips", ["<kbd>→</kbd>, <kbd>&gt;</kbd> - 后一章节",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - 後一章節",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - Next Chapter",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - Chapitre Suivant",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - Следующая глава",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - 次の章",
          "<kbd>→</kbd> / <kbd>&gt;</kbd> - 다음 장"
      ][_lang]);

      $(".mdx-bread-nav-text").attr("tips", ["回到本章节的开始",
          "回到本章節的開始",
          "Go back to the beginning of this chapter",
          "Retourner au début de ce chapitre",
          "Вернитесь к началу этой главы",
          "この章の始めに戻る",
          "이 장의 시작 부분으로 돌아 가기"
      ][_lang]);

      $(".mdx-btn-prev-figure").attr("title", ["[ ← ] - 前一张",
          "[ ← ] - 前一張",
          "[ ← ] - Previous",
          "[ ← ] - Précédent",
          "[ ← ] - Предыдущая фотографияs",
          "[ ← ] - 前へ",
          "[ ← ] - 이전"
      ][_lang]);

      $(".mdx-btn-next-figure").attr("title", ["[ → ] - 后一张",
          "[ → ] - 後一張",
          "[ → ] - Next",
          "[ → ] - Le suivant",
          "[ → ] - Следующий",
          "[ → ] - 次の",
          "[ → ] - 다음"
      ][_lang]);

      $(".mdx-btn-close-figure-viewer").attr("title", ["[ ESC ] - 关闭",
          "[ ESC ] - 關閉",
          "[ ESC ] - Close",
          "[ ESC ] - Fermer",
          "[ ESC ] - близко",
          "[ ESC ] - 閉じる",
          "[ ESC ] - 닫기"
      ][_lang]);

      $(".mdx-footer-note-toolbar a").text(["查看所有脚注 ▶",
          "查看所有腳註 ▶",
          "View all footnotes ▶",
          "Afficher toutes les notes de bas de page ▶",
          "Просмотреть все сноски ▶",
          "すべての脚注を見る ▶",
          "모든 각주보기 ▶"
      ][_lang]);

      $(".mdx-figure-action").attr("title", ["在新标签页中打开",
          "在新標籤頁中打開",
          "Open in new tab",
          "Ouvrir dans un nouvel onglet",
          "Открыть в новой вкладке",
          "新しいタブで開く",
          "새 탭에서 열기"
      ][_lang]);
  }

  /**
   * 根据设备类型自适应hover样式
   */
  function adjustHoverStyle() {
      // 移动设备时解绑样式事件
      if (env.device.mobile) {
          $(".mdx-btn, .mdx-nav-prev, .mdx-nav-next").unbind("mouseenter").unbind("mouseleave");
      }
      // 非移动设备时绑定样式事件
      else {
          // 按钮
          $(".mdx-btn").bind("mouseenter", function () {
              $(this).addClass("mdx-btn-hover");
          }).bind("mouseleave", function () {
              $(this).removeClass("mdx-btn-hover");
              $(this).addClass("mdx-btn-leave");
          });
      }
  }

  /**
   * 环境信息类
   */
  const env = {
      // Windows 平台样例：
      // (Chrome) Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
      // (Firefox) Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0
      // (Edge) Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
      //
      // macOS 平台样例：
      // (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
      // (Firefox) Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:69.0) Gecko/20100101 Firefox/69.0
      // (Safari) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.2 Safari/605.1.15
      //
      // 浏览器内核信息
      core: function () {
          const u = navigator.userAgent;
          return {
              trident: u.indexOf("Trident") > -1, //IE内核
              presto: u.indexOf("Presto") > -1, //opera内核
              webkit: u.indexOf("AppleWebKit") > -1, //苹果、谷歌内核
              gecko: u.indexOf("Gecko") > -1 && u.indexOf("KHTML") == -1 //火狐内核
          };
      }(),
      // 设备信息
      device: function () {
          const u = navigator.userAgent;
          return {
              mobile: !!u.match(/AppleWebKit.*Mobile.*/), // 是否为移动终端
              ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端
              android: u.indexOf("Android") > -1 || u.indexOf("Linux") > -1, // android终端或者uc浏览器
              iPhone: u.indexOf("iPhone") > -1, // 是否为iPhone或者QQHD浏览器
              iPad: u.indexOf("iPad") > -1 // 是否iPad
          };
      }(),
      // 浏览器类型
      browser: function () {
          const u = navigator.userAgent;
          return {
              chrome: u.indexOf("Chrome") > -1, // Chrome浏览器
              firefox: u.indexOf("Firefox") > -1, // Firefox浏览器
              safari: u.indexOf("Safari") > -1 && u.indexOf("Version") > -1 // Safari浏览器
          };
      }(),
      // 浏览器版本信息
      browserVersion: function () {
          const u = navigator.userAgent;
          return {
              chrome: u.match(/Chrome\/[\d.]+/gi) ? u.match(/Chrome\/[\d.]+/gi)[0].match(/[\d]+/)[0] :
              "0", // chrome浏览器版本
              firefox: u.match(/Firefox\/[\d.]+/gi) ? u.match(/Firefox\/[\d.]+/gi)[0].match(/[\d]+/)[0] :
              "0", // firefox浏览器版本
              safari: u.match(/Version\/[\d.]+.+Safari\/[\d.]+/gi) ? u.match(
                  /Version\/[\d.]+.+Safari\/[\d.]+/gi)[0].match(/[\d]+/)[0] : "0" // safari浏览器版本
          };
      }(),
      // 操作系统信息
      os: function () {
          const u = navigator.userAgent;
          return {
              windows: /windows|win32|win64/i.test(u), // 是否为windows平台
              macos: /macintosh|mac os x/i.test(u) // 是否为macOS平台
          };
      }(),
      // 语言信息
      language: function () {
          const lang = (navigator.browserLanguage || navigator.language);
          return {
              full: lang.toLowerCase(),
              base: lang.substring(0, 2),
              subset: lang.substring(3, lang.length)
          };
      }()
  }

  /**
   * 显示浏览器相关信息
   */
  function displayEnvInfo() {
      console.log("User-Agent\t[ " + navigator.userAgent + " ]");

      console.log("Language\t"
          + "[ " + env.language.base + (env.language.subset.length > 0 ? "_" + env.language.subset : "") + " ]");

      console.log("OS\t\t\t"
          + (env.os.macos ? "[ macOS ]" : "[ Windows ]"));

      console.log("Device\t\t"
          + "[ "
          + (env.device.mobile ? "Mobile " : "")
          + (env.device.ios ? "iOS " : "")
          + (env.device.android ? "Android " : "")
          + (env.device.iPhone ? "iPhone " : "")
          + (env.device.iPad ? "iPad " : "")
          + "]");

      console.log("Browser\t\t"
          + "[ "
          + (env.browser.chrome ? "Chrome " + env.browserVersion.chrome : "")
          + (env.browser.firefox ? "Firefox " + env.browserVersion.firefox : "")
          + (env.browser.safari ? "Safari " + env.browserVersion.safari : "")
          + " ]");

      console.log("Core\t\t"
          + "[ "
          + (env.core.gecko ? "Gecko" : "")
          + (env.core.presto ? "Presto" : "")
          + (env.core.trident ? "Trident" : "")
          + (env.core.webkit ? "WebKit" : "")
          + " ]");
  }

  /**
   * 初始化引用块以实现折叠支持
   */
  function initBlockquote() {
      $("blockquote > p").each(function () {
          let obj = $(this);
          // 默认收起
          if (obj.text().startWith("[+] ")) {
              obj.next("blockquote").css("display", "none");
              obj.html(obj.html().replace("[+] ", "▶ "));
              obj.attr("title", ["点击展开",
                  "點擊展開",
                  "Click to unfold",
                  "Cliquez pour agrandir",
                  "Нажмите, чтобы развернуть",
                  "クリックして拡大",
                  "확대하려면 클릭하십시오."
              ][_lang]);
              obj.addClass("mdx-blockquote-folder");
              obj.css("cursor", "pointer");
              obj.click(function () {
                  toggleQuoteFolding($(this));
              });
          }
          // 默认展开
          else if (obj.text().startWith("[-] ")) {
              obj.html(obj.html().replace("[-] ", "▼ "));
              obj.attr("title", ["点击收起",
                  "點擊收起",
                  "Click to fold",
                  "Cliquez pour fermer",
                  "Нажмите, чтобы закрыть",
                  "閉じる",
                  "닫기를 클릭하십시오"
              ][_lang]);
              obj.addClass("mdx-blockquote-folder");
              obj.css("cursor", "pointer");
              obj.click(function () {
                  toggleQuoteFolding($(this));
              });
          }
      });
  }

  /**
   * 展开/收起引用块
   */
  function toggleQuoteFolding(obj) {
      let quote = obj.next("blockquote");
      quote.css("display") == "none" ? unfoldQuote(obj, quote) : foldQuote(obj, quote);
  }

  /**
   * 收起引用块
   */
  function foldQuote(obj, quote) {
      console.log("fold: " + quote.css("display"));
      quote.css("display", "none");
      obj.attr("title", ["点击展开",
          "點擊展開",
          "Click to unfold",
          "Cliquez pour agrandir",
          "Нажмите, чтобы развернуть",
          "クリックして拡大",
          "확대하려면 클릭하십시오."
      ][_lang]);
      obj.html(obj.html().replace("▼ ", "▶ "));
  }

  /**
   * 展开引用块
   */
  function unfoldQuote(obj, quote) {
      console.log("unFold: " + quote.css("display"));
      quote.css("display", "block");
      obj.attr("title", ["点击收起",
          "點擊收起",
          "Click to fold",
          "Cliquez pour fermer",
          "Нажмите, чтобы закрыть",
          "閉じる",
          "닫기를 클릭하십시오"
      ][_lang]);
      obj.html(obj.html().replace("▶ ", "▼ "));
  }

  /**
   * 初始化外部链接（http://、https://、ftp://等），为其添加target参数
   */
  function initExtLink() {
      $("a[href^='http']").each(function () {
          if (!$(this).attr("target"))
              $(this).attr("target", "_blank");
      });
      $("a[href^='ftp']").each(function () {
          if (!$(this).attr("target"))
              $(this).attr("target", "_blank");
      });
  }

  /**
   * 显示/隐藏大纲面板
   */
  function toggleOutline() {
      if (isOutlineShowed())
          hideOutline();
      else
          showOutline();
  }

  /**
   * 显示outline
   */
  function showOutline() {
      _outlineShowed = true;
      let toc = $(".mdx-toc-box");
      if (isOutlineShowed() && parseInt(toc.css("left")) < 0) {
          // 显示大纲工具栏
          toc.addClass("mdx-float-card");
          toc.animate({
              left: 10 + _reboundOffset
          }, _animateSpeed).animate({
              left: 10
          }, _animateSpeed);

          if ($(window).width() < parseInt(toc.css("width")))
              toc.css("width", $(window).width() - 20);
          else
              toc.css("width", parseInt(getComputedStyle(document.documentElement).getPropertyValue("--toc-box-width")));

          // 显示遮罩
          showMask(toc, hideOutline);
      }
  }

  /**
   * 隐藏大纲
   */
  function hideOutline() {
      _outlineShowed = false;
      let toc = $(".mdx-toc-box");
      const tocBoxWidth = toc.width();
      if (!isOutlineShowed() && parseInt($(".mdx-toc-box").css("left")) > 0) {
          toc.animate({
              left: -tocBoxWidth
          }, _animateSpeed, function () {
              toc.removeClass("mdx-float-card");
          });

          hideMask();
      }
  }

  /**
   * 根据实际目录结构初始化大纲折叠控件folder
   */
  function initFolderButton() {
      let folder = null;
      for (let i = 0; i < _foldItem.length; i++) {
          folder = _foldItem[i].html(_icoUnfold);
          folder.parent().attr({
              "data-node": "1", // 0:leaf, 1:folder
              "data-folding": "1" // 0:collect, 1:expand
          });
          folder.click(function () {
              foldingChapter($(this).parent().attr("id"));
              event.cancelBubble = true;
          });
      }
  }

  /**
   * 页面滚动时高亮outline中的对应章节项
   */
  function followHeader() {
      let currentIndex = -1;

      // 寻找当前屏幕显示的章节
      for (let i = 0; i < _headers.length; i++) {
          let obj = env.browser.firefox == false
              ? $("a[name='" + _headers[i] + "']") // 非 Firefox 浏览器
              : $("a[name='" + decodeURI(_headers[i]) + "']"); // Firefox 浏览器
          let headerHeight = obj.parent().height();
          // 当前章节标题已滚过了屏幕顶部
          if ((obj.offset().top - $(document).scrollTop()) > (headerHeight / 2)) {
              currentIndex = i;
              break;
          }
      }

      // 当前章节未变更
      if (_lastCurrentHeaderIndex == currentIndex)
          return;

      _lastCurrentHeaderIndex = currentIndex;

      // 当前屏幕内容为第1章或以后章节的内容
      if (isFallInHeaders() == true) {
          // 根据是否为最后章节修正当前章节索引
          let currentIndex = _lastCurrentHeaderIndex > 0 ? (_lastCurrentHeaderIndex - 1) : (_headers.length - 1);

          // 清除大纲中上一次当前章节的样式
          if (_lastOutlineItem != null)
              _lastOutlineItem.removeClass("mdx-header-current");

          _lastOutlineItem = $("a[href='#" + _headers[currentIndex] + "']").parent();
          _lastOutlineItem.addClass("mdx-header-current");

          const tocBoxBody = $("#toc-box-body");
          const preDis = _lastOutlineItem.height() * 2;
          const sTop = tocBoxBody.scrollTop();
          const sBottom = sTop + tocBoxBody.height();

          if (_lastOutlineItem.position().top < sTop)
              $("#toc-box-body").scrollTop(_lastOutlineItem.position().top);
          else if (_lastOutlineItem.position().top > (sBottom - preDis))
              $("#toc-box-body").scrollTop(_lastOutlineItem.position().top - $("#toc-box-body").height() + preDis);

          // 更新面包屑导航UI及数据
          updateBreadNavUI(currentIndex);
      }

      adjustBreadNav();
  }

  /**
   * 是否落入章节内
   */
  function isFallInHeaders() {
      return _lastCurrentHeaderIndex > 0 || // 非最后章节
          (_lastCurrentHeaderIndex == -1 && _headers.length > 1); // 最后章节
  }

  /**
   * 更新面包屑导航UI及数据
   */
  function updateBreadNavUI(currentIndex) {
      // 更新导航栏内容
      let navText = $(".mdx-bread-nav-text");
      navText.text(_lastOutlineItem.attr("title"));
      navText.attr("data-anchor", _headers[currentIndex]);
      navText.click(function () {
          gotoHeader($(this));
      });

      // 面包屑导航：上一章
      let prev = $(".mdx-nav-prev");
      let prevText = $(".mdx-nav-prev-text");
      if (currentIndex > 0) {
          prev.css("display", "block");
          prevText.text($("a[href='#" + _headers[currentIndex - 1] + "']").parent().attr("title"));
          prevText.attr({
              "title": prevText.text(),
              "data-anchor": _headers[currentIndex - 1]
          });
      } else { // 当前章节为第1章时特殊处理
          prevText.text(["封面",
              "封面",
              "Cover",
              "Couverture",
              "передняя крышка",
              "カバー",
              "표지"
          ][_lang]);
          prevText.attr({
              "title": prevText.text(),
              "data-anchor": "cover"
          });
      }

      // 面包屑导航：下一章
      let next = $(".mdx-nav-next");
      let nextText = $(".mdx-nav-next-text");
      if (currentIndex < _headers.length - 1) {
          next.css("display", "block");
          nextText.text($("a[href='#" + _headers[currentIndex + 1] + "']").parent().attr("title"));
          nextText.attr({
              "title": nextText.text(),
              "data-anchor": _headers[currentIndex + 1]
          });
      } else
          next.css("display", "none");
  }

  /**
   * 显示工具提示信息
   */
  function showToolTips(msg, follow, align) {
      if (env.device.mobile == true)
          return;

      let toolTips = $(".mdx-tool-tips");
      hideTips(toolTips, true);
      toolTips.html(msg);

      const fp = follow.parent();
      const ow = toolTips.width();
      const ww = $(window).width();
      const gap = 30;
      let left = follow.offset().left;
      toolTips.css({
          "border-top-left-radius": "0",
          "border-top-right-radius": "15px"
      });

      // 指定对齐方式或提示超出屏幕
      if (align != null || (left + ow + gap) > ww) {
          // align: right
          toolTips.css({
              "border-top-left-radius": "15px",
              "border-top-right-radius": "0"
          });
          left = follow.offset().left - ow + follow.width() - gap;

          // align: center
          if (align == "center") {
              left = follow.offset().left + (follow.width() - ow) / 2 - gap / 2;
              toolTips.css({
                  "border-top-left-radius": "15px",
                  "border-top-right-radius": "15px"
              });
          }
      }

      toolTips.css({
          "left": left,
          "top": fp.offset().top - $(document).scrollTop() + fp.height() +
              (fp.css("background-color") == "rgba(0, 0, 0, 0)" ? 0 : 10)
      });
      toolTips.fadeIn(_animateSpeed);
  }

  /**
   * 显示通知提示信息
   */
  function showInfoTips(msg, delay, fullscreen) {
      clearTimeout(_tipsTimer);

      let obj = $(".mdx-info-tips");
      obj.html(msg);
      // 先重置为默认值
      obj.css({
          right: "auto",
          bottom: "auto",
          borderRadius: 15,
          lineHeight: "2em"
      });

      if (fullscreen == false) { // 居中显示
          obj.css({
              left: ($(window).width() - obj.width()) / 2,
              top: ($(window).height() - obj.height()) / 2
          });
      } else { // 全屏显示
          obj.css({
              left: 0,
              top: 0,
              right: 0,
              bottom: 0,
              borderRadius: 0
          });
          obj.css({
              lineHeight: obj.height() + "px"
          });
      }
      obj.fadeIn(_animateSpeed, function () {
          if (delay != null)
              _tipsTimer = setTimeout(function () {
                  hideTips(obj, true);
              }, delay);
      });
  }

  /**
   * 隐藏工具提示、弹窗信息
   */
  function hideTips(obj, ani) {
      if (ani == true)
          obj.fadeOut(_animateSpeed);
      else
          obj.hide();
  }

  /**
   * 显示面包屑导航
   */
  function showBreadNav() {
      let nav = $(".mdx-bread-nav");
      // 若已显示则跳过
      if (parseInt(nav.css("top")) >= 0)
          return;

      nav.addClass("mdx-float-card");
      // nav.css({top: -50});
      nav.animate({
          top: 0
      }, _animateSpeed);
  }

  /**
   * 隐藏面包屑导航
   */
  function hideBreadNav() {
      let nav = $(".mdx-bread-nav");
      if (parseInt(nav.css("top")) < 0)
          return;

      // 隐藏面包屑导航条
      nav.removeClass("mdx-float-card");
      nav.animate({
          top: -50
      }, _animateSpeed);
  }

  /**
   * 跳转至指定章节
   */
  function gotoHeader(obj) {
      let dataAnchor = obj.attr("data-anchor");
      if (dataAnchor == "cover")
          gotoTop();
      else
          window.location.href = "#" + obj.attr("data-anchor");
  }

  /**
   * 跳转至封面
   */
  function gotoTop() {
      $(window).scrollTop(0);
      if (_lastOutlineItem != null) {
          _lastOutlineItem.removeClass("mdx-header-current");
          // _lastOutlineItem.removeClass("mdx-header-current-dark");
          _lastCurrentHeaderIndex = -2;
      }
  }

  /**
   * 跳转至脚注区域
   */
  function gotoFooterArea() {
      hideFooterNote();
      window.location.href = "#xFooterArea";
  }

  /**
   * 返回上一个位置
   */
  function navBack() {
      window.history.back();
  }

  /**
   * 前去下一个位置
   */
  function navForward() {
      window.history.forward();
  }

  /**
   * 自适应显示工具栏
   */
  function adjustToolbar() {
      let tb = $(".mdx-toolbar");

      // 移动端下隐藏不必要的功能入口
      if (env.device.mobile == true)
          $(".mdx-btn-print, .mdx-btn-spotlight, .mdx-btn-font-style, .mdx-btn-color-scheme, .mdx-btn-print").hide();

      // 如果是小屏，或回到封面位置（面包屑已隐藏）
      if (isSmallScreen() || _lastCurrentHeaderIndex == 0) {
          $(".mdx-toolbar > div").addClass("mdx-float-card");

          // 小屏则直接隐藏背景
          if (isSmallScreen()) {
              tb.css({
                  background: "none"
              });
              tb.animate({
                  top: 50
              }, _animateSpeed);
          }
          // 大屏则动画式收起
          else {
              tb.css({
                  background: "none"
              });
          }

          tb.removeClass("mdx-backdrop-blurs");
          tb.removeClass("mdx-float-card");
          tb.animate({
              right: 10,
              width: $("#write").width() + 20
          }, _animateSpeed);

          if (_lastCurrentHeaderIndex == 0) // 如果回到封面位置（面包屑已隐藏），则进行二次调整
              tb.css({
                  top: 10
              });
      } else {
          $(".mdx-toolbar > div").removeClass("mdx-float-card");

          tb.css({
              // top: -50,
              backgroundColor: $(".mdx-bread-nav").css("background-color")
          });

          tb.addClass("mdx-backdrop-blurs");
          tb.addClass("mdx-float-card");
          tb.animate({
              top: 0,
              right: "auto",
              width: parseInt(getComputedStyle(document.documentElement).getPropertyValue("--toc-box-width"))
          }, _animateSpeed);
      }

      $(".mdx-btn-fullscreen").css("visibility", "visible");
      if (env.device.mobile)
          $(".mdx-btn-fullscreen").css("visibility", "hidden");
  }

  /**
   * 判断是否为小屏
   */
  function isSmallScreen() {
      return $(window).width() < _smallScreenWidth;
  }

  /**
   * 面包屑导航自适应显示
   */
  function adjustBreadNav() {
      let prev = $(".mdx-nav-prev");
      let prevText = $(".mdx-nav-prev-text");
      let next = $(".mdx-nav-next");
      let nextText = $(".mdx-nav-next-text");
      let nav = $(".mdx-bread-nav");
      let navText = $(".mdx-bread-nav-text");

      // 根据屏幕宽度显示/隐藏上下章节标题
      if (isSmallScreen()) {
          nav.css({
              left: 10
          });

          prevText.hide();
          nextText.hide();
          prev.css("width", "20%");
          next.css("width", "20%");

          // 调整面包屑导航样式
          navText.css({
              "margin-left": "40px",
              "margin-right": "40px"
          });
      } else {
          nav.css({
              left: "calc(var(--toc-box-width) + 30px)"
          });

          prevText.show();
          nextText.show();
          prev.css("width", "25%");
          next.css("width", "25%");

          // 调整面包屑导航样式
          navText.css({
              "margin-left": "200px",
              "margin-right": "200px"
          });
      }

      if (isFallInHeaders() == true) { // 最后章节
          // 显示面包屑导航
          showBreadNav();
          adjustToolbar();
      } else {
          // 隐藏面包屑导航
          hideBreadNav();
          adjustToolbar();
      }
  }

  /**
   * 收起/展开章节目录
   * @param id 对象的id值
   */
  function foldingChapter(id) {
      let obj = $("#" + id);
      let folder = $("#fd-" + id);
      const folding = obj.attr("data-folding");
      if (folding == "0") {
          obj.attr("data-folding", "1");
          folder.html(_icoUnfold);
          disposeFolding(id, 1, true);
      } else if (folding == "1") {
          obj.attr("data-folding", "0");
          folder.html(_icoFold);
          disposeFolding(id, 0, true);
      }
  }

  /**
   * 处理展开或收起指定ID下的子章节
   * @param id 对象的id值
   * @param act 动作：0=收起，1=展开
   * @param recu 是否遍历子元素
   */
  function disposeFolding(id, act, recu) {
      let lastItem = null;
      let itemSet = $("#" + id).nextAll();
      for (let i = 0; i < itemSet.length; i++) {
          let item = $(itemSet[i]);
          if (lastItem != null) {
              const hd1 = getCSSHeaderLevel(item);
              const hd2 = getCSSHeaderLevel(lastItem);
              if (hd1 > hd2)
                  continue;
              else if (hd1 < hd2)
                  break;
          }
          // 如果是目录节点，同时是已展开的，才进行递归调用展开子节点
          if (recu == true && item.attr("data-node") == "1" && item.attr("data-folding") == "1") {
              disposeFolding(item.attr("id"), act, recu);
          }
          if (act == 0) // 收起
              item.css("display", "none");
          else if (act == 1) // 展开
              item.css("display", "block");
          lastItem = item;
      }
  }

  /**
   * 返回指定对象的CSS的header的样式层级
   */
  function getCSSHeaderLevel(obj) {
      let cname = obj.attr("class");
      return cname.substr(cname.indexOf("md-toc-h") + "md-toc-h".length, 1)
  }

  /**
   * 更新任务列表的勾选框样式
   */
  function restyleTaskListCheckbox() {
      let obj = $(".md-task-list-item > input:disabled");
      obj.removeAttr("disabled");
      obj.css("pointer-events", "none");
  }

  /**
   * 更新指定内容的code标记样式
   */
  function restyleCode() {
      // 更新指定内容的<code>标签样式
      $("code").each(function () {
          // 将非英文竖线替换为半角
          if ($(this).text().length > 2) {
              $(this).text($(this).text().replaceAll("｜｜｜｜｜｜", " |||||| "));
              $(this).text($(this).text().replaceAll("｜｜｜｜｜", " ||||| "));
              $(this).text($(this).text().replaceAll("｜｜｜｜", " |||| "));
              $(this).text($(this).text().replaceAll("｜｜｜", " ||| "));
              $(this).text($(this).text().replaceAll("｜｜", " || "));
              $(this).text($(this).text().replaceAll("｜", " | "));
              $(this).text($(this).text().replaceAll("丨丨丨丨丨丨", " |||||| "));
              $(this).text($(this).text().replaceAll("丨丨丨丨丨", " ||||| "));
              $(this).text($(this).text().replaceAll("丨丨丨丨", " |||| "));
              $(this).text($(this).text().replaceAll("丨丨丨", " ||| "));
              $(this).text($(this).text().replaceAll("丨丨", " || "));
              $(this).text($(this).text().replaceAll("丨", " | "));
          }

          // ========== 药丸样式 ==========
          let codeText = $(this).text();
          // 新语法（风格2）
          let codeTags = new Array("==", "++", "**", "--", "!!", "##");
          let flag = false;
          for (let i = 0; i < codeTags.length; i++) {
              let si = codeText.indexOf(" | ");
              if (codeText.length > 7 &&
                  codeText.startWith(codeTags[i] + " ") &&
                  codeText.endWith(" " + codeTags[i]) &&
                  si > 2) {
                  rebuildSegmentCode2($(this), codeTags[i] + " ", si, "", i + 1);
                  flag = true;
                  break;
              }
          }
          // 新语法（风格1）
          if (flag == true) return;
          codeTags = new Array("=", "+", "*", "-", "!", "#");
          // flag = false;
          for (let i = 0; i < codeTags.length; i++) {
              const si = codeText.indexOf(" | ");
              if (codeText.length > 5 &&
                  codeText.startWith(codeTags[i] + " ") &&
                  codeText.endWith(" " + codeTags[i]) &&
                  si > 1) {
                  rebuildSegmentCode2($(this), codeTags[i] + " ", si, "", i + 1);
                  flag = true;
                  break;
              }
          }

          // ========== 标签式 ==========
          codeText = $(this).text();
          // 新语法（风格2）
          codeTags = new Array("==", "++", "**", "--", "!!", "##");
          // flag = false;
          for (let i = 0; i < codeTags.length; i++) {
              if (codeText.length > 6 && codeText.startWith(codeTags[i] + " ") && codeText.endWith(" " +
                      codeTags[i])) {
                  rebuildInlineCode($(this), codeTags[i] + " ", "", i + 1);
                  flag = true;
                  break;
              }
          }
          // 新语法（风格1）
          if (flag == true) return;
          codeTags = new Array("=", "+", "*", "-", "!", "#");
          // flag = false;
          for (let i = 0; i < codeTags.length; i++) {
              if (codeText.length > 4 && codeText.startWith(codeTags[i] + " ") && codeText.endWith(" " +
                      codeTags[i])) {
                  rebuildInlineCode($(this), codeTags[i] + " ", "", i + 1);
                  flag = true;
                  break;
              }
          }

          // ========== 药丸样式（旧语法）==========
          if (flag == true) return;
          codeTags = new Array(" | ", " || ", " ||| ", " |||| ", " ||||| ", " |||||| ");
          // flag = false;
          for (var i = 5; i >= 0; i--) {
              if (codeText.length > 5 && !codeText.startWith("`") && !codeText.endWith("`") && codeText
                  .indexOf(codeTags[i]) > 0) {
                  rebuildSegmentCode($(this), codeTags[i], i + 1);
                  flag = true;
                  break;
              }
          }

          // 普通标签增加样式标识，以用于深色模式时的识别
          if (flag == true)
              return;
          $(this).addClass("mdx-std-code");
      });
  }

  /**
   * 替换所有内容
   */
  String.prototype.replaceAll = function (f, e) {
      const reg = new RegExp(f, "g");
      return this.replace(reg, e);
  }

  /**
   * 以分类标签样式重新设置code的渲染样式（新语法）
   */
  function rebuildInlineCode(obj, split, flag, number) {
      const codeText = obj.text();
      const si = codeText.indexOf(split);
      obj.text(codeText.substring(si + split.length, codeText.length - split.length));
      obj.attr("class", "mdx-code-c" + number + flag);
  }

  /**
   * 以分类标签样式重新设置code block中指定内容的渲染样式（新语法）
   */
  function rebuildCodeFences(obj, split, flag, number) {
      const codeText = obj.text().substring(1, obj.text().length - 1);
      const si = codeText.indexOf(split);
      obj.text(codeText.substring(si + split.length, codeText.length - split.length));
      obj.attr("class", "mdx-code-c" + number + flag);
  }

  /**
   * 以药丸样式重建code标签结构与内容（旧语法）
   */
  function rebuildSegmentCode(obj, split, number) {
      const codeText = obj.text();
      const si = codeText.indexOf(split);
      obj.before("<code class='mdx-code-name" + number + "'>" + codeText.substr(0, si) + "</code>");
      obj.text(codeText.substr(si + split.length, codeText.length));
      obj.attr("class", "mdx-code-value" + number);
  }

  /**
   * 以药丸样式重建code标签结构与内容（新语法）
   */
  function rebuildSegmentCode2(obj, iden, si, flag, number) {
      const codeText = obj.text();
      obj.before("<code class='mdx-code-name" + number + flag + "'>" + codeText.substring(iden.length, si) +
          "</code>");
      obj.text(codeText.substring(si + 3, codeText.length - iden.length));
      obj.attr("class", "mdx-code-value" + number + flag);
  }

  /**
   * 更新指定内容的mermaid时序图的角色样式
   */
  function restyleMermaidStyle() {
      $(".md-diagram-panel svg[id^='mermaidChart'] > g > rect[class='actor']").each(function () {
          let textObj = $(this).next("text").children(); // actor rect object
          const person = /\@.*/g; // 人物
          const keySys = /\=.*\=/g; // 重点系统
          const extSys = /\-.*\-/g; // 外部系统

          // 更新<人物角色>样式
          if (person.test(textObj.text()) == true) {
              const h = $(this).height();
              $(this).css({
                  "rx": h / 2,
                  "ry": h / 2
              });
              textObj.text(textObj.text().substring(1, textObj.text().length));
          }
          // 更新 重点系统 样式
          else if (keySys.test(textObj.text()) == true) {
              $(this).css("stroke-width", "3"); // actor / rect
              textObj.css("font-weight", "bold"); // actor text
              textObj.text(textObj.text().substring(1, textObj.text().length - 1));
          }
          // 更新 外部系统 样式
          else if (extSys.test(textObj.text()) == true) {
              $(this).css("stroke-dasharray", "5 2"); // actor / rect
              textObj.text(textObj.text().substring(1, textObj.text().length - 1));
          }
      });

      // 更新loop/opt标签样式
      $(".md-diagram-panel svg g text[class='labelText'] > tspan").each(function () {
          const textObj = $(this);
          const g = textObj.parent().parent();
          // default opt
          let bgColor = $(".mdx-color-third-alt").css("color");
          let borderColor = $(".mdx-color-third-fade").css("color");
          let textColor = $(".mdx-color-third").css("color");
          if (textObj.text() == "loop") { // loop
              bgColor = $(".mdx-color-fourth-alt").css("color");
              borderColor = $(".mdx-color-fourth-fade").css("color");
              textColor = $(".mdx-color-fourth").css("color");
          }
          if (textObj.text() == "loop" || textObj.text() == "opt") {
              g.children("polygon.labelBox").css("fill", bgColor);
              g.children("line.loopLine").css("stroke", borderColor);
              g.children("text.labelText").css("fill", textColor);
              g.children("text.labelText").children("tspan").css("fill", textColor);
              g.children("text.loopText").children("tspan").css("fill", textColor);
          }
      });

      // 为兼容Firefox不支持在style中设置rx, ry，通过设置rect的rx, ry属性
      // 针对mermaid的状态图节点、子图
      $("#START rect, #END rect, #INIT ~ g > rect, .cluster rect").each(function () {
          $(this).attr({
              "rx": 15,
              "ry": 15
          });
      });

      // 修正高 DPI 导出的 mermaid 的BUG
      fixHighDPImermaid();
  }

  /**
   * 修正 mermaid 8.0 在 Windows 高 DPI 配置下导出的BUG
  */
  function fixHighDPImermaid() {
      // 跳过非 Windows 版 Typora 导出的 HTML
      if ($("body").attr("class").indexOf("os-windows") == -1)
          return;
  
      $(".label foreignObject > div, .edgeLabel foreignObject > div").each(function () {
          // 跳过空文本的处理
          if ($(this).text().trim().length == 0)
              return true;

          let ratio = $(this).parent().height() / $(this).height(), // 获得文本标签及父元素的高度比，作为line-height的基数
              child = $(this).children("span"), // 获得线条上的文本标签对象
              coefficient = 2; // 行高、字号就调节系数

          // 跳过指定的比例情况
          console.log("Mermaid Scale Ratio: " + ratio);
          if (ratio <= 1) {
              // 对于特定环境的修正
              if (ratio < 1 && env.browser.chrome && env.os.windows) {
                  $(this).parent().css("height", "2em");
                  $(this).parent().css("line-height", "1em");
              }
              return true;
          }

          // 如果当前是非高清屏，对于高 DPI 导出的文件，再修正缩放比例
          if (getDPR() == 1 && env.browser.chrome && env.os.windows) {
              ratio = ratio / 2;
              console.log("Mermaid Scale Ratio (alt): " + ratio);
          }

          if (child.length == 0) { // 非线条上的文本标签
              if (env.browser.chrome && env.os.windows) {
                  coefficient = 2;
                  ratio = ratio * coefficient; // 行高基数 * 2
              }
              $(this).css("line-height", (ratio / coefficient / 0.9) + "em");
              $(this).css("font-size", (ratio / coefficient * 0.9) + "em");
          }
          else { // 线条上的文本标签
              if (env.browser.chrome && env.os.windows) {
                  coefficient = 4;
                  ratio = ratio * coefficient; // 行高基数 * 4
                  child.css("line-height", (ratio / coefficient / 0.5) + "em");
                  child.css("font-size", (ratio / coefficient) + "em");
              }
              else if (env.browser.chrome && env.os.macos
                  || env.browser.firefox) {
                  coefficient = 2;
                  ratio = ratio * coefficient; // 行高基数 * 2
                  child.css("line-height", (ratio / coefficient / 0.9) + "em");
                  child.css("font-size", (ratio / coefficient / coefficient * 0.9) + "em");
              }
          }
      });
  }

  /**
   * 更新多行代码块code block/fences样式
   * 主要处理三类情况：
   * 1. span包裹标准格式全部内容。如：`= sourcecode =`
   * 2. span分别包裹标准格式的不同部分。如：(`)(=) (sourcecode) (=)(`)
   * 3. span包裹标准格式及其他所有内容。如：sourcecode`= sourcecode =`sourcecode
   */
  function restyleCodeFences() {
      $("span[class^='cm-']").each(function () {
          const reg = /`[=|\+|\*|\-|\!|#] (([^`])+[a-z]|[A-Z]|[\S])+ [=|\+|\*|\-|\!|#]`/g;
          let codeTags = new Array("=", "+", "*", "-", "!", "#");
          let result = $(this).text().match(reg);
          if (result != null) {
              const codeText = $(this).text().substring(1, $(this).text().length - 1);
              for (var i = 0; i < codeTags.length; i++) {
                  if (codeText.length > 4 && codeText.startWith(codeTags[i] + " ") && codeText.endWith(" " +
                          codeTags[i])) {
                      rebuildCodeFences($(this), codeTags[i] + " ", "", i + 1);
                      break;
                  }
              }
          }
      });
  }

  /**
   * 打开/关闭聚光灯
   */
  function toggleSpotlight() {
      const obj = $(".mdx-spotlight");
      if (obj.css("display") == "none") {
          obj.show();
          const e = window.event;

          if (e.clientX != undefined) {
              _spotlightX = e.clientX;
              _spotlightY = e.clientY;
          }
          repaintSpotlight();
      } else {
          obj.hide();
      }
  }

  /**
   * 切换字体样式
   */
  function toggleFontStyle() {
      const fontInfo = "<br/>──<br/><span style='font-size: 0.8em'>" + ["VLOOK 优先显示开源的思源黑体和思源宋体<br/>建议下载安装获得更好的视觉体验",
              "VLOOK 優先顯示開源的思源黑體和思源宋體<br/>建議用戶下載安裝獲得更好的視覺體驗",
              "VLOOK gives priority to the Noto Sans and Noto Serif<br/>suggesting to download and install for a better visual experience",
              "VLOOK donne la priorité à Noto Sans et Noto Serif,<br/>suggérant de télécharger et d'installer pour une meilleure expérience visuelle",
              "VLOOKUP отдает приоритет Noto Sans и Noto Serif,<br/>предлагая загрузить и установить для лучшего визуального восприятия",
              "VLOOK は、Noto SansとNoto Serifを優先し<br/>より良い視覚的経験のためにダウンロードしてインストールすることを提案します",
              "VLOOK 은 노토 산 (Noto Sans)과 노토 세리프 (Noto Serif)를<br/>우선시하여 더 나은 시각적 경험을 위해 다운로드하여 설치하도록 제안합니다"
          ][_lang] +
          "</span><br/><a href='https://github.com/MadMaxChow/VLOOK/blob/master/FONT.md' target='_blank'>" + ["下载",
              "下載",
              "Download",
              "Télécharger",
              "скачать",
              "ダウンロード",
              "다운로드"
          ][_lang] + "</a>";

      if ($("body").attr("class").indexOf("mdx-font-text-sans") == -1) {
          showInfoTips(["切换至 <b>非衬线</b> 字体",
                  "切換至 <b>非襯線</b> 字體",
                  "Switch to <b>Sans</b> Font",
                  "Basculer vers <b>Sans</b> Fuente",
                  "Переключиться на <b>шрифт без засечек</b>",
                  "に切り替える <b>Sans</b> フォント",
                  "전환 <b>Sans</b> 글꼴"
              ][_lang] + fontInfo,
              5000, false);
          applyFontStyle("sans");
      } else {
          showInfoTips(["切换至 <b>衬线</b> 字体",
                  "切換至 <b>襯線</b> 字體",
                  "Switch to <b>Serif</b> Font",
                  "Basculer vers <b>Serif</b> Police",
                  "Переключиться на шрифт <b>печать</b>",
                  "に切り替える <b>Serif</b> フォント",
                  "전환 <b>Serif</b> 폰트"
              ][_lang] + fontInfo,
              5000, false);
          applyFontStyle("serif");
      }
  }

  /**
   * 应用指定字体样式
   * @style: sans-非衬线，serif-衬线
   */
  function applyFontStyle(style) {
      const text =
          "html, body, text[text-anchor=\"start\"] > tspan, .edgeLabel, .messageText, .noteText, .noteText tspan, .MathJax_SVG g text";
      const title = "#write > h6:first-of-type, #write > h6:last-of-type";
      const tag =
          ".mdx-code-c1, .mdx-code-c2, .mdx-code-c3, .mdx-code-c4, .mdx-code-c5, .mdx-code-c6, .mdx-code-name1-alt, .mdx-code-name2-alt, .mdx-code-name3-alt, .mdx-code-name4-alt, .mdx-code-name5-alt, .mdx-code-name6-alt, .mdx-code-name1, .mdx-code-name2, .mdx-code-name3, .mdx-code-name4, .mdx-code-name5, .mdx-code-name6, .mdx-code-value1-alt, .mdx-code-value2-alt, .mdx-code-value3-alt, .mdx-code-value4-alt, .mdx-code-value5-alt, .mdx-code-value6-alt, .mdx-code-value1, .mdx-code-value2, .mdx-code-value3, .mdx-code-value4, .mdx-code-value5, .mdx-code-value6";
      const header = "h1, h2, h3, h4, h5, h6";
      const bold =
          "strong, #write > h6:first-of-type strong, #write > h6:first-of-type em, table tr th, .mdx-table-td-bold, .mdx-toc-box-title, .mdx-toc-box-header, .mdx-loading-done, .mdx-tool-tips, .mdx-info-tips, .mdx-toc-box-header, .mdx-bread-nav-text, .mdx-nav-prev-text, .mdx-nav-next-text, .mdx-toc-box-title, .mdx-figure-alt > span, rect + text[text-anchor=\"middle\"] > tspan, rect + rect + text[text-anchor=\"middle\"] > tspan, .outline-item, a[name^=\"ref-footnote-\"], .md-toc-h1, .md-toc-h2, .md-toc-h3, .md-toc-h4, .md-toc-h5, .md-fn-count, .mdx-toc-box-footer, mdx-copyright";
      const code = "code, tt, .md-fences, kbd";

      if (_currentFontStyle != null) {
          $(code).removeClass("mdx-font-code-" + _currentFontStyle);
          $(tag).removeClass("mdx-font-code-" + _currentFontStyle);
          $(tag).removeClass("mdx-font-bold-" + _currentFontStyle);
          $(text).removeClass("mdx-font-text-" + _currentFontStyle);
          $(header).removeClass("mdx-font-header-" + _currentFontStyle);
          $(title).removeClass("mdx-font-title-" + _currentFontStyle);
          $(bold).removeClass("mdx-font-bold-" + _currentFontStyle);
      }
      _currentFontStyle = style;
      $(".mdx-btn-font-style").html("<svg width='18px' height='16px'><use xlink:href='#icoFont-" + style +
          "' class='mdx-svg-ico-light'/></svg>");

      $(code).addClass("mdx-font-code-" + style);
      $(tag).removeClass("mdx-font-code-" + _currentFontStyle);
      $(tag).addClass("mdx-font-bold-" + style);
      $(text).addClass("mdx-font-text-" + style);
      $(header).addClass("mdx-font-header-" + style);
      $(title).addClass("mdx-font-title-" + style);
      $(bold).addClass("mdx-font-bold-" + style);

      localStorage["VLOOK-" + _version + "-font-style"] = _currentFontStyle;
  }

  /**
   * 切换颜色方案
   */
  function toggleColorShmeme() {
      _colorScheme = (_colorScheme == "light") ? "dark" : "light";

      if (_colorScheme == "dark") {
          showInfoTips(["正在切换为：<strong>黑暗模式</strong>",
                  "正在切換為：<strong>黑暗模式</strong>",
                  "Switching to: <strong>Dark Mode</strong>",
                  "Passer à: <strong>Mode Sombre</strong>",
                  "Переключение на: <strong>Темный режим</strong>",
                  "切り替え先：<strong>ダークモード</strong>",
                  "로 전환 : <strong>다크 모드</strong>"
              ][_lang],
              2000, true);

          $(".md-diagram-panel svg").removeClass("mdx-figure-bg-light");
          $(".md-diagram-panel svg").addClass("mdx-figure-bg-dark");
      } else {
          showInfoTips(["正在切换为：<strong>明亮模式</strong>",
                  "正在切換為：<strong>明亮模式</strong>",
                  "Switching to: <strong>Light Mode</strong>",
                  "Passer à: <strong>Mode lumière</strong>",
                  "Переключение на: <strong>Легкий режим</strong>",
                  "切り替え先：<strong>ライトモード</strong>",
                  "로 전환 : <strong>라이트 모드</strong>"
              ][_lang],
              2000, true);

          $(".md-diagram-panel svg").removeClass("mdx-figure-bg-dark");
          $(".md-diagram-panel svg").addClass("mdx-figure-bg-light");
      }

      // 延时再开始，以便让UI先完成更新
      setTimeout(adjustColorScheme, 500);
  }

  /**
   * 更新颜色方案UI
   */
  function updateColorSchemeUI() {
      if (_colorScheme == "dark") {
          // 调整模式切换按钮图标
          $(".mdx-btn-color-scheme").html(
              "<svg width='18px' height='18px'><use xlink:href='#icoDarkMode' class='mdx-svg-ico-light'/></svg>");
      } else {
          // 调整模式切换按钮图标
          $(".mdx-btn-color-scheme").html(
              "<svg width='20px' height='20px'><use xlink:href='#icoLightMode' class='mdx-svg-ico-light'/></svg>");
      }
  }

  /**
   * 根据浏览器当前的颜色方案进行适配
   */
  function adjustColorScheme() {
      const varList = [
          "--doc-bg-color",
          "--doc-bg-color-alt",
          "--doc-bg-color-alt-transparent",
          "--fore-color",
          "--tips-bg-color",
          "--tips-bg-color-inset",
          "--shadow-color",
          "--a-color",
          "--a-line-color",
          "--a-active-color",
          "--theme-bg-color-fade",
          "--footer-note-bg-color",
          "--table-border-color",
          "--table-th-bg-color",
          "--table-th-border-color",
          "--img-dark-filter",
          "--del-color",
          "--toc-header-num-color",
          "--content-header-num-color",
          "--header-color",
          "--header-box-shadow",
          "--header-bg-start-color",
          "--header-bg-end-color",
          "--code-bg-color",
          "--code-bg-color-transparent",
          "--code-name-bg-color",
          "--code-name-shadow-color",
          "--master-color",
          "--slave-color",
          "--third-color",
          "--fourth-color",
          "--fifth-color",
          "--sixth-color",
          "--mermaid-master-color",
          "--mermaid-master-color-alt",
          "--mermaid-slave-color",
          "--mermaid-slave-color-alt",
          "--mermaid-third-color",
          "--mermaid-third-color-alt",
          "--mermaid-fourth-color",
          "--mermaid-fourth-color-alt",
          "--mermaid-fifth-color",
          "--mermaid-fifth-color-alt",
          "--mermaid-sixth-color",
          "--mermaid-sixth-color-alt"
      ];

      // 遍历所有变量实现ColorScheme切换
      for (let i = 0; i < varList.length; i++) {
          document.documentElement.style.setProperty(varList[i], getComputedStyle(document.documentElement)
              .getPropertyValue(varList[i] + "-" + _colorScheme));
      }

      adjustImageInverInDarkMode();

      updateColorSchemeUI();
  }

  /**
   * 适配指定图片在 Dark Mode 的反转处理
   */
  function adjustImageInverInDarkMode() {
      if (_colorScheme == "dark") {
          // 应用 Dark 模式的插图背景
          // $(".md-diagram-panel svg").removeClass("mdx-figure-bg-light");
          // $(".md-diagram-panel svg").addClass("mdx-figure-bg-dark");

          $("img[vlook-invert=in-dark]").addClass("mdx-img-invert-in-dark");
      } else {
          // 恢复Light模式插图背景
          // $(".md-diagram-panel svg").removeClass("mdx-figure-bg-dark");
          // $(".md-diagram-panel svg").addClass("mdx-figure-bg-light");

          $("img[vlook-invert=in-dark]").removeClass("mdx-img-invert-in-dark");
      }
  }

  /**
   * 大纲是否已显示
   */
  function isOutlineShowed() {
      return _outlineShowed;
  }

  /**
   * 增强脚注
   */
  function initFooterNote() {
      let fontnotesArea = $(".footnotes-area");
      // 将脚注调整到封底前
      fontnotesArea.insertBefore($("#write > h6:last"));

      // 移除默认的跳转属性
      let aFontnote = $("a[name^='ref-footnote-']");
      aFontnote.removeAttr("href");

      // 将脚注角标的事件替换为指定的处理事件
      let fontnoteContent = $(".mdx-footer-note-content");
      let fontnoteToolbar = $(".mdx-footer-note-toolbar");
      aFontnote.click(function () {
          var obj = $("a[name='df" + $(this).attr("name") + "']").parent().clone();

          // 更新脚注弹层内容
          fontnoteContent.html(obj);
          obj.find("a[name^='dfref-footnote']")[0].remove(); // 移除默认的返回链接

          // 显示脚注弹层
          showFooterNote();

          updateScroolBottomShadow(fontnoteContent, fontnoteToolbar, 30);
      });

      // outline内容滚动时，根据内容是否滚动未结束，未结束时添加阴影效果
      $(".mdx-footer-note-content").scroll(function () {
          updateScroolBottomShadow(fontnoteContent, fontnoteToolbar, 30);
      });

      // 将脚注区锚点调整到生成HTML后的实际位置
      $("a[name='xFooterArea']").insertBefore(fontnotesArea);
  }

  /**
   * 更新聚光灯显示
   */
  function repaintSpotlight(e) {
      let spot = $(".mdx-spotlight");
      spot.css("background", "radial-gradient(circle at " +
          _spotlightX + "px " + _spotlightY + "px, " +
          "rgba(0, 0, 0, 0) " + _spotlightR + "px, " +
          "rgba(0, 0, 0, 0.7)" + (_spotlightR + 1) + "px)");
  }

  /**
   * 显示脚注弹层
   */
  function showFooterNote() {
      let footerNote = $(".mdx-footer-note");
      showMask(footerNote, hideFooterNote);

      if (isSmallScreen())
          footerNote.css({
              "left": "20px",
              "right": "20px"
          });
      else
          footerNote.css({
              "left": "15%",
              "right": "15%"
          });

      footerNote.show().animate({
          bottom: 80 + _reboundOffset
      }, _animateSpeed).animate({
          bottom: 80
      }, _animateSpeed);
  }

  /**
   * 冻结文档，不允选择和滚动
   */
  function freezeScroll() {
      $("body").css({
          // "user-select": "none", // 禁用网页选择
          "overflow": "hidden" // 禁用网页滚动
      });
  }

  /**
   * 显示遮罩
   */
  function showMask(under, callback) {
      freezeScroll();

      // 显示遮罩
      let mask = $(".mdx-mask");
      mask.css("z-index", under.css("z-index") - 1);
      mask.on("click", callback);
      mask.fadeIn(_animateSpeed);
  }

  /**
   * 解冻文档，恢复选择和滚动
   */
  function unfreezeScroll() {
      $("body").css({
          "user-select": "text", // 恢复网页选择
          "overflow": "auto" // 恢复网页滚动
      });
  }

  /**
   * 隐藏遮罩
   */
  function hideMask() {
      unfreezeScroll();

      // 隐藏遮罩
      let mask = $(".mdx-mask");
      mask.off("click");
      mask.fadeOut(_animateSpeed);
  }

  /**
   * 隐藏脚注弹层
   */
  function hideFooterNote() {
      let footerNote = $(".mdx-footer-note");
      footerNote.animate({
          bottom: -150
      }, _animateSpeed, function () {
          hideMask();
          $(this).hide();
      });
  }

  /**
   * 初始化热键
   */
  function initHotkeys() {
      // 键盘按下事件
      $(document).keydown(function (event) {
          const code = event.keyCode || event.which || event.charCode;
          // console.log(code);
console.log(_blockFocusItemIndex);
          // 按了组合键时忽略
          if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey)
              return;

          switch (code) {
              case 74: // J
                  nextBlockFocusItem(1); // 步长1
                  break;
              case 75: // K
                  prevBlockFocusItem(1); // 步长1
                  break;
              case 72: // H
                  prevBlockFocusItem(10); // 步长10，快速移动
                  break;
              case 76: // L
                  nextBlockFocusItem(10); // 步长10，快速移动
                  break;
              case 188: // <
              case 37: // ←
                  if ($(".mdx-figure-viewer").css("display") == "block")
                      prevFigure();
                  else
                      gotoHeader($(".mdx-nav-prev-text"));
                  break;
              case 190: // >
              case 39: // →
                  if ($(".mdx-figure-viewer").css("display") == "block")
                      nextFigure();
                  else {
                      if (parseInt($(".mdx-bread-nav").css("top")) < 0)
                          $(".mdx-nav-next-text").attr("data-anchor", _headers[0]);
                      gotoHeader($(".mdx-nav-next-text"));
                  }
                  break;
              case 79: // O
                  hideFigureViewer();
                  toggleOutline();
                  break;
              case 73: // I
                  hideOutline();
                  if ($(".mdx-figure-viewer").css("display") == "none")
                      showFigureViewer();
                  else
                      hideFigureViewer();
                  break;
              case 84: // T
                  toggleColorShmeme();
                  break;
              case 65: // A
                  toggleFontStyle();
                  break;
              case 80: // P
                  printDocument();
                  break;
              case 83: // S
                  toggleSpotlight();
                  break;
              case 13: // ENTER
                  if (_blockFocusItemIndex > -1) {
                      var obj = $("#mdx-blockfocus-" + _blockFocusItemIndex);
                      if (obj.attr("class").indexOf("mdx-blockquote-folder") != -1)
                          obj.click();
                  }
                  break;
              case 27: // ESC
                  var spot = $(".mdx-spotlight");
                  hideTips($(".mdx-tool-tips"), true);
                  hideTips($(".mdx-info-tips"), true);
                  if (spot.css("display") == "block")
                      spot.hide();
                  else if ($(".mdx-figure-viewer").css("display") == "block")
                      hideFigureViewer();
                  else {
                      if (isOutlineShowed())
                          hideOutline();

                      hideTableCross();

                      hideBlockFocus();
                      _enableBlockFocus = false;
                  }
                  break;
              case 90: // Z
                  _spotlightR = _spotlightR > 180 ? 180 : 240;
                  repaintSpotlight();
                  break;
          }
      });
  }

  /**
   * 隐藏聚焦内容块
   */
  function hideBlockFocus() {
      if (_lastBlockFocusItem != null)
          _lastBlockFocusItem.removeClass("mdx-current-blockfocus-item");
      _lastBlockFocusItem = null;
  }

  /**
   * 获取url中的参数
   */
  function getQueryString(urlqs) {
      let qs = urlqs.substr(1), // 获取url中"?"符后的字串
          args = {}, // 保存参数数据的对象
          items = (qs.length > 0) ? qs.split("&") : [], // 取得每一个参数项,
          item = null,
          len = items.length;

      for (let i = 0; i < len; i++) {
          item = items[i].split("=");
          let name = decodeURIComponent(item[0]),
              value = decodeURIComponent(item[1]);
          if (name) {
              args[name] = value;
          }
      }
      return args;
  }

  /**
   * 关闭
   */
  function closeLoadingScreen() {
      unfreezeScroll();
      $(".mdx-loading").fadeOut(_animateSpeed);
  }

  /**
   * 打印文档
   */
  function printDocument() {
      // 若当前为 Dark 模式则强制临时切换为 Light 模式
      if (_colorScheme == "dark") {
          _colorSchemeBeforePrint = _colorScheme;
          _colorScheme = "light";
          adjustColorScheme();
      }
      window.print();
  }

  /**
   * 初始化 VLOOK
   */
  function initVLOOK(colorScheme) {
      // 锁定滚动
      freezeScroll();

      // 初始化国际化UI
      initUIi18n();

      // 检查页内链接坏链
      checkInnerBadLink();
      // 检查重复的Header
      checkDuplicateHeader();

      // 初始化插图数据
      initFigureData();
      console.log("init FigureData " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化列表
      initBlockFocus();
      console.log("init BlockFocus " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化表格
      initTable();
      console.log("init Table " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化引用块
      initBlockquote();
      console.log("init Blockquote " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化外部链接
      initExtLink();
      console.log("init ExtLink " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 增强脚注
      initFooterNote();
      console.log("init FooterNote " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化全局热键
      initHotkeys();
      console.log("init Hotkeys " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 重置脚本化图表样式
      restyleMermaidStyle();
      console.log("init MermaidStyle " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 重置行内代码code样式
      restyleCode();
      // 重置多行代码块code block样式
      restyleCodeFences();
      console.log("init RestyleCode/Fences " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 重置任务列表样式
      restyleTaskListCheckbox();
      console.log("init TaskListCheckbox " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 初始化Outline数据
      if (initOutlineData()) {
          // 更新Outline上的目录节点按钮
          initFolderButton();

          // 更新工具栏标题
          $(".mdx-toc-box-title").text($(document).attr("title"));

          // 自适应页面内容显示
          followHeader();
          adjustBreadNav();
          adjustToolbar();

          console.log("init OutlineData " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
          _lastTimer = new Date().getTime();
      }

      // 根据设备类型自适应hover样式
      adjustHoverStyle();
      console.log("init Hover Style " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 设置字体样式
      const style = localStorage["VLOOK-" + _version + "-font-style"];
      if (window.localStorage && style != undefined)
          applyFontStyle(style);
      else
          applyFontStyle("serif");
      console.log("init Font Style " + ((new Date().getTime() - _lastTimer) / 1000) + "s");
      _lastTimer = new Date().getTime();

      // 隐藏插图动作按钮
      hideFigureAction(null);

      // 绑定文档鼠标移动事件，聚光灯跟随鼠标移动
      document.addEventListener("mousemove", function () {
          let spotlight = $(".mdx-spotlight");
          const e = window.event;
          _spotlightX = e.clientX;
          _spotlightY = e.clientY;
          if (spotlight.css("display") == "block") {
              repaintSpotlight();
          }
      });

      // 绑定文档的滚动事件
      $(document).scroll(function () {
          followHeader();

          let tb = $(".mdx-toolbar");
          // 如果回到文档开始位置
          if ($(document).scrollTop() <= 10) {
              tb.css({
                  top: 10
              });
          } else if (isFallInHeaders() == false) {
              tb.css({
                  top: 0
              });
          }
      });

      // 绑定窗口大小缩放事件
      $(window).resize(function () {
      });

      // 绑定打印前的触发事件
      window.onbeforeprint = function() {
      };
      // 绑定打印后的触发事件
      window.onafterprint = function() {
          if (_colorSchemeBeforePrint == "dark") {
              _colorScheme = _colorSchemeBeforePrint;
              adjustColorScheme();
          }
      };

      // 清空历史存储
      if (getQueryString(location.search)["reset"] == "ls") {
          console.log("!!! Reset Local Storage !!!");
          localStorage.removeItem("VLOOK-" + _version + "-hint-for-green-hand-step-bf");
      }

      console.log("[ DONE ] Total " + ((new Date().getTime() - _startTimer) / 1000) + "s");

      let loadDone = $(".mdx-loading-done");
      loadDone.animate({
          opacity: 1
      }, _animateSpeed, function () {
          $(".mdx-loading").css("cursor", "default");
      });
// <!--
//       loadDone.text(["轻一点，轻轻一点",
//           "輕一點，輕輕一點",
//           "Click to Start",
//           "Cliquez pour commencer",
//           "Нажмите, чтобы начать",
//           "クリックして開始",
//           "클릭하여 시작"
//       ][_lang]);
// -->
      loadDone.css("cursor", "pointer");
      loadDone.click(function () {
          closeLoadingScreen();
      });
      // 完成加载后自动延时关闭欢迎屏
      setTimeout(closeLoadingScreen, 5000);

      // 应用于在新标签中打开内容时初始化颜色模式
      if (colorScheme != null)
          _colorScheme = colorScheme;
  }

  /**
   * HTML文档加载完成后执行主流程
   */
  $(document).ready(function () {
      // 显示环境信息
      displayEnvInfo();

      // 显示当前设备的DPR值
      console.log("DPR (Device Pixel Ratio): " + getDPR());

      // 推荐的浏览器类型检测
      if (env.browser.chrome == false &&
          env.browser.firefox == false &&
          env.browser.safari == false) {
          alert(["为获得最佳兼容性，建议使用 Chrome / Firefox / Safari 浏览器",
              "為獲得最佳兼容性，建議使用 Chrome / Firefox / Safari / Safari 瀏覽器",
              "For best compatibility, we recommend using Chrome / Firefox / Safari",
              "Pour une meilleure compatibilité, nous vous recommandons d’utiliser Chrome / Firefox / Safari",
              "Для лучшей совместимости мы рекомендуем использовать Chrome / Firefox / Safari",
              "最高の互換性を得るために、 Chrome / Firefox / Safari の使用をお勧めします",
              "최상의 호환성을 위해 Chrome / Firefox / Safari 사용을 권장합니다."
          ][_lang]);
      }

      // 推荐的浏览器版本号检测
      let readyForBackgroundBlurs = false
      if (env.browser.chrome == true && parseInt(env.browserVersion.chrome) >= 76)
          readyForBackgroundBlurs = true;
      else if (env.browser.safari == true && parseInt(env.browserVersion.safari) >= 9)
          readyForBackgroundBlurs = true;
      if (readyForBackgroundBlurs == false) {
          alert(["浏览器版本过低（Chrome 76.0+, Safari 9.0+, Firefox 不支持），不支持部分界面的毛玻璃效果",
              "瀏覽器版本過低（Chrome 76.0+, Safari 9.0+, Firefox 不支持），不支持部分界面的毛玻璃效果",
              "Browser version is too low (Chrome 76.0+, Safari 9.0+, Firefox does not support), does not support the frosted glass effect of some interfaces",
              "La version du navigateur est trop basse (Chrome 76.0+, Safari 9.0+, Firefox ne prend pas en charge), ne prend pas en charge l'effet de verre dépoli de certaines interfaces",
              "Версия браузера слишком низкая (Chrome 76.0+, Safari 9.0+, Firefox не поддерживает), не поддерживает эффект матового стекла некоторых интерфейсов",
              "ブラウザのバージョンが低すぎる（Chrome 76.0以降、Safari 9.0以降、Firefoxはサポートしていません）、一部のインターフェイスのつや消しガラス効果をサポートしていません",
              "브라우저 버전이 너무 낮습니다 (Chrome 76.0 이상, Safari 9.0 이상, Firefox는 지원하지 않음). 일부 인터페이스의 젖빛 유리 효과를 지원하지 않습니다"
          ][_lang]);
      }

      // 初始化 VLOOK
      console.log("init VLOOK ...");
      initVLOOK();

      // 因默认配色为Light模式，若浏览器当前配色为Dark模式，则进行初始化适配
      _colorScheme = getComputedStyle(document.documentElement).getPropertyValue("--vlook-color-scheme")
          .replaceAll("\"", "").trim();
      console.log("Color Scheme: " + _colorScheme);
      if (_colorScheme == "dark")
          updateColorSchemeUI();

      adjustImageInverInDarkMode();
  });